Commit d09042da7284a86ffbdd18695f517a71514ed598
Committed by
Linus Torvalds
1 parent
785d55708c
Exists in
master
and in
4 other branches
[PATCH] fix incorrect SA_ONSTACK behaviour for 64-bit processes
- When setting a sighandler using sigaction() call, if the flag SA_ONSTACK is set and no alternate stack is provided via sigaltstack(), the kernel still try to install the alternate stack. This behavior is the opposite of the one which is documented in Single Unix Specifications V3. - Also when setting an alternate stack using sigaltstack() with the flag SS_DISABLE, the kernel try to install the alternate stack on signal delivery. These two use cases makes the process crash at signal delivery. Signed-off-by: Laurent Meyer <meyerlau@fr.ibm.com> Cc: Richard Henderson <rth@twiddle.net> Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru> Cc: David Howells <dhowells@redhat.com> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Roman Zippel <zippel@linux-m68k.org> Cc: Kyle McMartin <kyle@mcmartin.ca> Cc: Paul Mundt <lethal@linux-sh.org> Cc: Kazumoto Kojima <kkojima@rr.iij4u.or.jp> Cc: Chris Zankel <chris@zankel.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 9 changed files with 9 additions and 9 deletions Inline Diff
arch/alpha/kernel/signal.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/alpha/kernel/signal.c | 2 | * linux/arch/alpha/kernel/signal.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1995 Linus Torvalds | 4 | * Copyright (C) 1995 Linus Torvalds |
| 5 | * | 5 | * |
| 6 | * 1997-11-02 Modified for POSIX.1b signals by Richard Henderson | 6 | * 1997-11-02 Modified for POSIX.1b signals by Richard Henderson |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/signal.h> | 11 | #include <linux/signal.h> |
| 12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
| 13 | #include <linux/wait.h> | 13 | #include <linux/wait.h> |
| 14 | #include <linux/ptrace.h> | 14 | #include <linux/ptrace.h> |
| 15 | #include <linux/unistd.h> | 15 | #include <linux/unistd.h> |
| 16 | #include <linux/mm.h> | 16 | #include <linux/mm.h> |
| 17 | #include <linux/smp.h> | 17 | #include <linux/smp.h> |
| 18 | #include <linux/smp_lock.h> | 18 | #include <linux/smp_lock.h> |
| 19 | #include <linux/stddef.h> | 19 | #include <linux/stddef.h> |
| 20 | #include <linux/tty.h> | 20 | #include <linux/tty.h> |
| 21 | #include <linux/binfmts.h> | 21 | #include <linux/binfmts.h> |
| 22 | #include <linux/bitops.h> | 22 | #include <linux/bitops.h> |
| 23 | 23 | ||
| 24 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
| 25 | #include <asm/sigcontext.h> | 25 | #include <asm/sigcontext.h> |
| 26 | #include <asm/ucontext.h> | 26 | #include <asm/ucontext.h> |
| 27 | 27 | ||
| 28 | #include "proto.h" | 28 | #include "proto.h" |
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | #define DEBUG_SIG 0 | 31 | #define DEBUG_SIG 0 |
| 32 | 32 | ||
| 33 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 33 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 34 | 34 | ||
| 35 | asmlinkage void ret_from_sys_call(void); | 35 | asmlinkage void ret_from_sys_call(void); |
| 36 | static int do_signal(sigset_t *, struct pt_regs *, struct switch_stack *, | 36 | static int do_signal(sigset_t *, struct pt_regs *, struct switch_stack *, |
| 37 | unsigned long, unsigned long); | 37 | unsigned long, unsigned long); |
| 38 | 38 | ||
| 39 | 39 | ||
| 40 | /* | 40 | /* |
| 41 | * The OSF/1 sigprocmask calling sequence is different from the | 41 | * The OSF/1 sigprocmask calling sequence is different from the |
| 42 | * C sigprocmask() sequence.. | 42 | * C sigprocmask() sequence.. |
| 43 | * | 43 | * |
| 44 | * how: | 44 | * how: |
| 45 | * 1 - SIG_BLOCK | 45 | * 1 - SIG_BLOCK |
| 46 | * 2 - SIG_UNBLOCK | 46 | * 2 - SIG_UNBLOCK |
| 47 | * 3 - SIG_SETMASK | 47 | * 3 - SIG_SETMASK |
| 48 | * | 48 | * |
| 49 | * We change the range to -1 .. 1 in order to let gcc easily | 49 | * We change the range to -1 .. 1 in order to let gcc easily |
| 50 | * use the conditional move instructions. | 50 | * use the conditional move instructions. |
| 51 | * | 51 | * |
| 52 | * Note that we don't need to acquire the kernel lock for SMP | 52 | * Note that we don't need to acquire the kernel lock for SMP |
| 53 | * operation, as all of this is local to this thread. | 53 | * operation, as all of this is local to this thread. |
| 54 | */ | 54 | */ |
| 55 | asmlinkage unsigned long | 55 | asmlinkage unsigned long |
| 56 | do_osf_sigprocmask(int how, unsigned long newmask, struct pt_regs *regs) | 56 | do_osf_sigprocmask(int how, unsigned long newmask, struct pt_regs *regs) |
| 57 | { | 57 | { |
| 58 | unsigned long oldmask = -EINVAL; | 58 | unsigned long oldmask = -EINVAL; |
| 59 | 59 | ||
| 60 | if ((unsigned long)how-1 <= 2) { | 60 | if ((unsigned long)how-1 <= 2) { |
| 61 | long sign = how-2; /* -1 .. 1 */ | 61 | long sign = how-2; /* -1 .. 1 */ |
| 62 | unsigned long block, unblock; | 62 | unsigned long block, unblock; |
| 63 | 63 | ||
| 64 | newmask &= _BLOCKABLE; | 64 | newmask &= _BLOCKABLE; |
| 65 | spin_lock_irq(¤t->sighand->siglock); | 65 | spin_lock_irq(¤t->sighand->siglock); |
| 66 | oldmask = current->blocked.sig[0]; | 66 | oldmask = current->blocked.sig[0]; |
| 67 | 67 | ||
| 68 | unblock = oldmask & ~newmask; | 68 | unblock = oldmask & ~newmask; |
| 69 | block = oldmask | newmask; | 69 | block = oldmask | newmask; |
| 70 | if (!sign) | 70 | if (!sign) |
| 71 | block = unblock; | 71 | block = unblock; |
| 72 | if (sign <= 0) | 72 | if (sign <= 0) |
| 73 | newmask = block; | 73 | newmask = block; |
| 74 | if (_NSIG_WORDS > 1 && sign > 0) | 74 | if (_NSIG_WORDS > 1 && sign > 0) |
| 75 | sigemptyset(¤t->blocked); | 75 | sigemptyset(¤t->blocked); |
| 76 | current->blocked.sig[0] = newmask; | 76 | current->blocked.sig[0] = newmask; |
| 77 | recalc_sigpending(); | 77 | recalc_sigpending(); |
| 78 | spin_unlock_irq(¤t->sighand->siglock); | 78 | spin_unlock_irq(¤t->sighand->siglock); |
| 79 | 79 | ||
| 80 | regs->r0 = 0; /* special no error return */ | 80 | regs->r0 = 0; /* special no error return */ |
| 81 | } | 81 | } |
| 82 | return oldmask; | 82 | return oldmask; |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | asmlinkage int | 85 | asmlinkage int |
| 86 | osf_sigaction(int sig, const struct osf_sigaction __user *act, | 86 | osf_sigaction(int sig, const struct osf_sigaction __user *act, |
| 87 | struct osf_sigaction __user *oact) | 87 | struct osf_sigaction __user *oact) |
| 88 | { | 88 | { |
| 89 | struct k_sigaction new_ka, old_ka; | 89 | struct k_sigaction new_ka, old_ka; |
| 90 | int ret; | 90 | int ret; |
| 91 | 91 | ||
| 92 | if (act) { | 92 | if (act) { |
| 93 | old_sigset_t mask; | 93 | old_sigset_t mask; |
| 94 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 94 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
| 95 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 95 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
| 96 | __get_user(new_ka.sa.sa_flags, &act->sa_flags)) | 96 | __get_user(new_ka.sa.sa_flags, &act->sa_flags)) |
| 97 | return -EFAULT; | 97 | return -EFAULT; |
| 98 | __get_user(mask, &act->sa_mask); | 98 | __get_user(mask, &act->sa_mask); |
| 99 | siginitset(&new_ka.sa.sa_mask, mask); | 99 | siginitset(&new_ka.sa.sa_mask, mask); |
| 100 | new_ka.ka_restorer = NULL; | 100 | new_ka.ka_restorer = NULL; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 103 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
| 104 | 104 | ||
| 105 | if (!ret && oact) { | 105 | if (!ret && oact) { |
| 106 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 106 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
| 107 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 107 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
| 108 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags)) | 108 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags)) |
| 109 | return -EFAULT; | 109 | return -EFAULT; |
| 110 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | 110 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | return ret; | 113 | return ret; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | asmlinkage long | 116 | asmlinkage long |
| 117 | sys_rt_sigaction(int sig, const struct sigaction __user *act, | 117 | sys_rt_sigaction(int sig, const struct sigaction __user *act, |
| 118 | struct sigaction __user *oact, | 118 | struct sigaction __user *oact, |
| 119 | size_t sigsetsize, void __user *restorer) | 119 | size_t sigsetsize, void __user *restorer) |
| 120 | { | 120 | { |
| 121 | struct k_sigaction new_ka, old_ka; | 121 | struct k_sigaction new_ka, old_ka; |
| 122 | int ret; | 122 | int ret; |
| 123 | 123 | ||
| 124 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 124 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
| 125 | if (sigsetsize != sizeof(sigset_t)) | 125 | if (sigsetsize != sizeof(sigset_t)) |
| 126 | return -EINVAL; | 126 | return -EINVAL; |
| 127 | 127 | ||
| 128 | if (act) { | 128 | if (act) { |
| 129 | new_ka.ka_restorer = restorer; | 129 | new_ka.ka_restorer = restorer; |
| 130 | if (copy_from_user(&new_ka.sa, act, sizeof(*act))) | 130 | if (copy_from_user(&new_ka.sa, act, sizeof(*act))) |
| 131 | return -EFAULT; | 131 | return -EFAULT; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 134 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
| 135 | 135 | ||
| 136 | if (!ret && oact) { | 136 | if (!ret && oact) { |
| 137 | if (copy_to_user(oact, &old_ka.sa, sizeof(*oact))) | 137 | if (copy_to_user(oact, &old_ka.sa, sizeof(*oact))) |
| 138 | return -EFAULT; | 138 | return -EFAULT; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | return ret; | 141 | return ret; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | /* | 144 | /* |
| 145 | * Atomically swap in the new signal mask, and wait for a signal. | 145 | * Atomically swap in the new signal mask, and wait for a signal. |
| 146 | */ | 146 | */ |
| 147 | asmlinkage int | 147 | asmlinkage int |
| 148 | do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw) | 148 | do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw) |
| 149 | { | 149 | { |
| 150 | sigset_t oldset; | 150 | sigset_t oldset; |
| 151 | 151 | ||
| 152 | mask &= _BLOCKABLE; | 152 | mask &= _BLOCKABLE; |
| 153 | spin_lock_irq(¤t->sighand->siglock); | 153 | spin_lock_irq(¤t->sighand->siglock); |
| 154 | oldset = current->blocked; | 154 | oldset = current->blocked; |
| 155 | siginitset(¤t->blocked, mask); | 155 | siginitset(¤t->blocked, mask); |
| 156 | recalc_sigpending(); | 156 | recalc_sigpending(); |
| 157 | spin_unlock_irq(¤t->sighand->siglock); | 157 | spin_unlock_irq(¤t->sighand->siglock); |
| 158 | 158 | ||
| 159 | /* Indicate EINTR on return from any possible signal handler, | 159 | /* Indicate EINTR on return from any possible signal handler, |
| 160 | which will not come back through here, but via sigreturn. */ | 160 | which will not come back through here, but via sigreturn. */ |
| 161 | regs->r0 = EINTR; | 161 | regs->r0 = EINTR; |
| 162 | regs->r19 = 1; | 162 | regs->r19 = 1; |
| 163 | 163 | ||
| 164 | while (1) { | 164 | while (1) { |
| 165 | current->state = TASK_INTERRUPTIBLE; | 165 | current->state = TASK_INTERRUPTIBLE; |
| 166 | schedule(); | 166 | schedule(); |
| 167 | if (do_signal(&oldset, regs, sw, 0, 0)) | 167 | if (do_signal(&oldset, regs, sw, 0, 0)) |
| 168 | return -EINTR; | 168 | return -EINTR; |
| 169 | } | 169 | } |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | asmlinkage int | 172 | asmlinkage int |
| 173 | do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize, | 173 | do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize, |
| 174 | struct pt_regs *regs, struct switch_stack *sw) | 174 | struct pt_regs *regs, struct switch_stack *sw) |
| 175 | { | 175 | { |
| 176 | sigset_t oldset, set; | 176 | sigset_t oldset, set; |
| 177 | 177 | ||
| 178 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 178 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
| 179 | if (sigsetsize != sizeof(sigset_t)) | 179 | if (sigsetsize != sizeof(sigset_t)) |
| 180 | return -EINVAL; | 180 | return -EINVAL; |
| 181 | if (copy_from_user(&set, uset, sizeof(set))) | 181 | if (copy_from_user(&set, uset, sizeof(set))) |
| 182 | return -EFAULT; | 182 | return -EFAULT; |
| 183 | 183 | ||
| 184 | sigdelsetmask(&set, ~_BLOCKABLE); | 184 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 185 | spin_lock_irq(¤t->sighand->siglock); | 185 | spin_lock_irq(¤t->sighand->siglock); |
| 186 | oldset = current->blocked; | 186 | oldset = current->blocked; |
| 187 | current->blocked = set; | 187 | current->blocked = set; |
| 188 | recalc_sigpending(); | 188 | recalc_sigpending(); |
| 189 | spin_unlock_irq(¤t->sighand->siglock); | 189 | spin_unlock_irq(¤t->sighand->siglock); |
| 190 | 190 | ||
| 191 | /* Indicate EINTR on return from any possible signal handler, | 191 | /* Indicate EINTR on return from any possible signal handler, |
| 192 | which will not come back through here, but via sigreturn. */ | 192 | which will not come back through here, but via sigreturn. */ |
| 193 | regs->r0 = EINTR; | 193 | regs->r0 = EINTR; |
| 194 | regs->r19 = 1; | 194 | regs->r19 = 1; |
| 195 | 195 | ||
| 196 | while (1) { | 196 | while (1) { |
| 197 | current->state = TASK_INTERRUPTIBLE; | 197 | current->state = TASK_INTERRUPTIBLE; |
| 198 | schedule(); | 198 | schedule(); |
| 199 | if (do_signal(&oldset, regs, sw, 0, 0)) | 199 | if (do_signal(&oldset, regs, sw, 0, 0)) |
| 200 | return -EINTR; | 200 | return -EINTR; |
| 201 | } | 201 | } |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | asmlinkage int | 204 | asmlinkage int |
| 205 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) | 205 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) |
| 206 | { | 206 | { |
| 207 | return do_sigaltstack(uss, uoss, rdusp()); | 207 | return do_sigaltstack(uss, uoss, rdusp()); |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | /* | 210 | /* |
| 211 | * Do a signal return; undo the signal stack. | 211 | * Do a signal return; undo the signal stack. |
| 212 | */ | 212 | */ |
| 213 | 213 | ||
| 214 | #if _NSIG_WORDS > 1 | 214 | #if _NSIG_WORDS > 1 |
| 215 | # error "Non SA_SIGINFO frame needs rearranging" | 215 | # error "Non SA_SIGINFO frame needs rearranging" |
| 216 | #endif | 216 | #endif |
| 217 | 217 | ||
| 218 | struct sigframe | 218 | struct sigframe |
| 219 | { | 219 | { |
| 220 | struct sigcontext sc; | 220 | struct sigcontext sc; |
| 221 | unsigned int retcode[3]; | 221 | unsigned int retcode[3]; |
| 222 | }; | 222 | }; |
| 223 | 223 | ||
| 224 | struct rt_sigframe | 224 | struct rt_sigframe |
| 225 | { | 225 | { |
| 226 | struct siginfo info; | 226 | struct siginfo info; |
| 227 | struct ucontext uc; | 227 | struct ucontext uc; |
| 228 | unsigned int retcode[3]; | 228 | unsigned int retcode[3]; |
| 229 | }; | 229 | }; |
| 230 | 230 | ||
| 231 | /* If this changes, userland unwinders that Know Things about our signal | 231 | /* If this changes, userland unwinders that Know Things about our signal |
| 232 | frame will break. Do not undertake lightly. It also implies an ABI | 232 | frame will break. Do not undertake lightly. It also implies an ABI |
| 233 | change wrt the size of siginfo_t, which may cause some pain. */ | 233 | change wrt the size of siginfo_t, which may cause some pain. */ |
| 234 | extern char compile_time_assert | 234 | extern char compile_time_assert |
| 235 | [offsetof(struct rt_sigframe, uc.uc_mcontext) == 176 ? 1 : -1]; | 235 | [offsetof(struct rt_sigframe, uc.uc_mcontext) == 176 ? 1 : -1]; |
| 236 | 236 | ||
| 237 | #define INSN_MOV_R30_R16 0x47fe0410 | 237 | #define INSN_MOV_R30_R16 0x47fe0410 |
| 238 | #define INSN_LDI_R0 0x201f0000 | 238 | #define INSN_LDI_R0 0x201f0000 |
| 239 | #define INSN_CALLSYS 0x00000083 | 239 | #define INSN_CALLSYS 0x00000083 |
| 240 | 240 | ||
| 241 | static long | 241 | static long |
| 242 | restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | 242 | restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
| 243 | struct switch_stack *sw) | 243 | struct switch_stack *sw) |
| 244 | { | 244 | { |
| 245 | unsigned long usp; | 245 | unsigned long usp; |
| 246 | long i, err = __get_user(regs->pc, &sc->sc_pc); | 246 | long i, err = __get_user(regs->pc, &sc->sc_pc); |
| 247 | 247 | ||
| 248 | sw->r26 = (unsigned long) ret_from_sys_call; | 248 | sw->r26 = (unsigned long) ret_from_sys_call; |
| 249 | 249 | ||
| 250 | err |= __get_user(regs->r0, sc->sc_regs+0); | 250 | err |= __get_user(regs->r0, sc->sc_regs+0); |
| 251 | err |= __get_user(regs->r1, sc->sc_regs+1); | 251 | err |= __get_user(regs->r1, sc->sc_regs+1); |
| 252 | err |= __get_user(regs->r2, sc->sc_regs+2); | 252 | err |= __get_user(regs->r2, sc->sc_regs+2); |
| 253 | err |= __get_user(regs->r3, sc->sc_regs+3); | 253 | err |= __get_user(regs->r3, sc->sc_regs+3); |
| 254 | err |= __get_user(regs->r4, sc->sc_regs+4); | 254 | err |= __get_user(regs->r4, sc->sc_regs+4); |
| 255 | err |= __get_user(regs->r5, sc->sc_regs+5); | 255 | err |= __get_user(regs->r5, sc->sc_regs+5); |
| 256 | err |= __get_user(regs->r6, sc->sc_regs+6); | 256 | err |= __get_user(regs->r6, sc->sc_regs+6); |
| 257 | err |= __get_user(regs->r7, sc->sc_regs+7); | 257 | err |= __get_user(regs->r7, sc->sc_regs+7); |
| 258 | err |= __get_user(regs->r8, sc->sc_regs+8); | 258 | err |= __get_user(regs->r8, sc->sc_regs+8); |
| 259 | err |= __get_user(sw->r9, sc->sc_regs+9); | 259 | err |= __get_user(sw->r9, sc->sc_regs+9); |
| 260 | err |= __get_user(sw->r10, sc->sc_regs+10); | 260 | err |= __get_user(sw->r10, sc->sc_regs+10); |
| 261 | err |= __get_user(sw->r11, sc->sc_regs+11); | 261 | err |= __get_user(sw->r11, sc->sc_regs+11); |
| 262 | err |= __get_user(sw->r12, sc->sc_regs+12); | 262 | err |= __get_user(sw->r12, sc->sc_regs+12); |
| 263 | err |= __get_user(sw->r13, sc->sc_regs+13); | 263 | err |= __get_user(sw->r13, sc->sc_regs+13); |
| 264 | err |= __get_user(sw->r14, sc->sc_regs+14); | 264 | err |= __get_user(sw->r14, sc->sc_regs+14); |
| 265 | err |= __get_user(sw->r15, sc->sc_regs+15); | 265 | err |= __get_user(sw->r15, sc->sc_regs+15); |
| 266 | err |= __get_user(regs->r16, sc->sc_regs+16); | 266 | err |= __get_user(regs->r16, sc->sc_regs+16); |
| 267 | err |= __get_user(regs->r17, sc->sc_regs+17); | 267 | err |= __get_user(regs->r17, sc->sc_regs+17); |
| 268 | err |= __get_user(regs->r18, sc->sc_regs+18); | 268 | err |= __get_user(regs->r18, sc->sc_regs+18); |
| 269 | err |= __get_user(regs->r19, sc->sc_regs+19); | 269 | err |= __get_user(regs->r19, sc->sc_regs+19); |
| 270 | err |= __get_user(regs->r20, sc->sc_regs+20); | 270 | err |= __get_user(regs->r20, sc->sc_regs+20); |
| 271 | err |= __get_user(regs->r21, sc->sc_regs+21); | 271 | err |= __get_user(regs->r21, sc->sc_regs+21); |
| 272 | err |= __get_user(regs->r22, sc->sc_regs+22); | 272 | err |= __get_user(regs->r22, sc->sc_regs+22); |
| 273 | err |= __get_user(regs->r23, sc->sc_regs+23); | 273 | err |= __get_user(regs->r23, sc->sc_regs+23); |
| 274 | err |= __get_user(regs->r24, sc->sc_regs+24); | 274 | err |= __get_user(regs->r24, sc->sc_regs+24); |
| 275 | err |= __get_user(regs->r25, sc->sc_regs+25); | 275 | err |= __get_user(regs->r25, sc->sc_regs+25); |
| 276 | err |= __get_user(regs->r26, sc->sc_regs+26); | 276 | err |= __get_user(regs->r26, sc->sc_regs+26); |
| 277 | err |= __get_user(regs->r27, sc->sc_regs+27); | 277 | err |= __get_user(regs->r27, sc->sc_regs+27); |
| 278 | err |= __get_user(regs->r28, sc->sc_regs+28); | 278 | err |= __get_user(regs->r28, sc->sc_regs+28); |
| 279 | err |= __get_user(regs->gp, sc->sc_regs+29); | 279 | err |= __get_user(regs->gp, sc->sc_regs+29); |
| 280 | err |= __get_user(usp, sc->sc_regs+30); | 280 | err |= __get_user(usp, sc->sc_regs+30); |
| 281 | wrusp(usp); | 281 | wrusp(usp); |
| 282 | 282 | ||
| 283 | for (i = 0; i < 31; i++) | 283 | for (i = 0; i < 31; i++) |
| 284 | err |= __get_user(sw->fp[i], sc->sc_fpregs+i); | 284 | err |= __get_user(sw->fp[i], sc->sc_fpregs+i); |
| 285 | err |= __get_user(sw->fp[31], &sc->sc_fpcr); | 285 | err |= __get_user(sw->fp[31], &sc->sc_fpcr); |
| 286 | 286 | ||
| 287 | return err; | 287 | return err; |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | /* Note that this syscall is also used by setcontext(3) to install | 290 | /* Note that this syscall is also used by setcontext(3) to install |
| 291 | a given sigcontext. This because it's impossible to set *all* | 291 | a given sigcontext. This because it's impossible to set *all* |
| 292 | registers and transfer control from userland. */ | 292 | registers and transfer control from userland. */ |
| 293 | 293 | ||
| 294 | asmlinkage void | 294 | asmlinkage void |
| 295 | do_sigreturn(struct sigcontext __user *sc, struct pt_regs *regs, | 295 | do_sigreturn(struct sigcontext __user *sc, struct pt_regs *regs, |
| 296 | struct switch_stack *sw) | 296 | struct switch_stack *sw) |
| 297 | { | 297 | { |
| 298 | sigset_t set; | 298 | sigset_t set; |
| 299 | 299 | ||
| 300 | /* Verify that it's a good sigcontext before using it */ | 300 | /* Verify that it's a good sigcontext before using it */ |
| 301 | if (!access_ok(VERIFY_READ, sc, sizeof(*sc))) | 301 | if (!access_ok(VERIFY_READ, sc, sizeof(*sc))) |
| 302 | goto give_sigsegv; | 302 | goto give_sigsegv; |
| 303 | if (__get_user(set.sig[0], &sc->sc_mask)) | 303 | if (__get_user(set.sig[0], &sc->sc_mask)) |
| 304 | goto give_sigsegv; | 304 | goto give_sigsegv; |
| 305 | 305 | ||
| 306 | sigdelsetmask(&set, ~_BLOCKABLE); | 306 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 307 | spin_lock_irq(¤t->sighand->siglock); | 307 | spin_lock_irq(¤t->sighand->siglock); |
| 308 | current->blocked = set; | 308 | current->blocked = set; |
| 309 | recalc_sigpending(); | 309 | recalc_sigpending(); |
| 310 | spin_unlock_irq(¤t->sighand->siglock); | 310 | spin_unlock_irq(¤t->sighand->siglock); |
| 311 | 311 | ||
| 312 | if (restore_sigcontext(sc, regs, sw)) | 312 | if (restore_sigcontext(sc, regs, sw)) |
| 313 | goto give_sigsegv; | 313 | goto give_sigsegv; |
| 314 | 314 | ||
| 315 | /* Send SIGTRAP if we're single-stepping: */ | 315 | /* Send SIGTRAP if we're single-stepping: */ |
| 316 | if (ptrace_cancel_bpt (current)) { | 316 | if (ptrace_cancel_bpt (current)) { |
| 317 | siginfo_t info; | 317 | siginfo_t info; |
| 318 | 318 | ||
| 319 | info.si_signo = SIGTRAP; | 319 | info.si_signo = SIGTRAP; |
| 320 | info.si_errno = 0; | 320 | info.si_errno = 0; |
| 321 | info.si_code = TRAP_BRKPT; | 321 | info.si_code = TRAP_BRKPT; |
| 322 | info.si_addr = (void __user *) regs->pc; | 322 | info.si_addr = (void __user *) regs->pc; |
| 323 | info.si_trapno = 0; | 323 | info.si_trapno = 0; |
| 324 | send_sig_info(SIGTRAP, &info, current); | 324 | send_sig_info(SIGTRAP, &info, current); |
| 325 | } | 325 | } |
| 326 | return; | 326 | return; |
| 327 | 327 | ||
| 328 | give_sigsegv: | 328 | give_sigsegv: |
| 329 | force_sig(SIGSEGV, current); | 329 | force_sig(SIGSEGV, current); |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | asmlinkage void | 332 | asmlinkage void |
| 333 | do_rt_sigreturn(struct rt_sigframe __user *frame, struct pt_regs *regs, | 333 | do_rt_sigreturn(struct rt_sigframe __user *frame, struct pt_regs *regs, |
| 334 | struct switch_stack *sw) | 334 | struct switch_stack *sw) |
| 335 | { | 335 | { |
| 336 | sigset_t set; | 336 | sigset_t set; |
| 337 | 337 | ||
| 338 | /* Verify that it's a good ucontext_t before using it */ | 338 | /* Verify that it's a good ucontext_t before using it */ |
| 339 | if (!access_ok(VERIFY_READ, &frame->uc, sizeof(frame->uc))) | 339 | if (!access_ok(VERIFY_READ, &frame->uc, sizeof(frame->uc))) |
| 340 | goto give_sigsegv; | 340 | goto give_sigsegv; |
| 341 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 341 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| 342 | goto give_sigsegv; | 342 | goto give_sigsegv; |
| 343 | 343 | ||
| 344 | sigdelsetmask(&set, ~_BLOCKABLE); | 344 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 345 | spin_lock_irq(¤t->sighand->siglock); | 345 | spin_lock_irq(¤t->sighand->siglock); |
| 346 | current->blocked = set; | 346 | current->blocked = set; |
| 347 | recalc_sigpending(); | 347 | recalc_sigpending(); |
| 348 | spin_unlock_irq(¤t->sighand->siglock); | 348 | spin_unlock_irq(¤t->sighand->siglock); |
| 349 | 349 | ||
| 350 | if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw)) | 350 | if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw)) |
| 351 | goto give_sigsegv; | 351 | goto give_sigsegv; |
| 352 | 352 | ||
| 353 | /* Send SIGTRAP if we're single-stepping: */ | 353 | /* Send SIGTRAP if we're single-stepping: */ |
| 354 | if (ptrace_cancel_bpt (current)) { | 354 | if (ptrace_cancel_bpt (current)) { |
| 355 | siginfo_t info; | 355 | siginfo_t info; |
| 356 | 356 | ||
| 357 | info.si_signo = SIGTRAP; | 357 | info.si_signo = SIGTRAP; |
| 358 | info.si_errno = 0; | 358 | info.si_errno = 0; |
| 359 | info.si_code = TRAP_BRKPT; | 359 | info.si_code = TRAP_BRKPT; |
| 360 | info.si_addr = (void __user *) regs->pc; | 360 | info.si_addr = (void __user *) regs->pc; |
| 361 | info.si_trapno = 0; | 361 | info.si_trapno = 0; |
| 362 | send_sig_info(SIGTRAP, &info, current); | 362 | send_sig_info(SIGTRAP, &info, current); |
| 363 | } | 363 | } |
| 364 | return; | 364 | return; |
| 365 | 365 | ||
| 366 | give_sigsegv: | 366 | give_sigsegv: |
| 367 | force_sig(SIGSEGV, current); | 367 | force_sig(SIGSEGV, current); |
| 368 | } | 368 | } |
| 369 | 369 | ||
| 370 | 370 | ||
| 371 | /* | 371 | /* |
| 372 | * Set up a signal frame. | 372 | * Set up a signal frame. |
| 373 | */ | 373 | */ |
| 374 | 374 | ||
| 375 | static inline void __user * | 375 | static inline void __user * |
| 376 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | 376 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) |
| 377 | { | 377 | { |
| 378 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) | 378 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) |
| 379 | sp = current->sas_ss_sp + current->sas_ss_size; | 379 | sp = current->sas_ss_sp + current->sas_ss_size; |
| 380 | 380 | ||
| 381 | return (void __user *)((sp - frame_size) & -32ul); | 381 | return (void __user *)((sp - frame_size) & -32ul); |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | static long | 384 | static long |
| 385 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | 385 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
| 386 | struct switch_stack *sw, unsigned long mask, unsigned long sp) | 386 | struct switch_stack *sw, unsigned long mask, unsigned long sp) |
| 387 | { | 387 | { |
| 388 | long i, err = 0; | 388 | long i, err = 0; |
| 389 | 389 | ||
| 390 | err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack); | 390 | err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack); |
| 391 | err |= __put_user(mask, &sc->sc_mask); | 391 | err |= __put_user(mask, &sc->sc_mask); |
| 392 | err |= __put_user(regs->pc, &sc->sc_pc); | 392 | err |= __put_user(regs->pc, &sc->sc_pc); |
| 393 | err |= __put_user(8, &sc->sc_ps); | 393 | err |= __put_user(8, &sc->sc_ps); |
| 394 | 394 | ||
| 395 | err |= __put_user(regs->r0 , sc->sc_regs+0); | 395 | err |= __put_user(regs->r0 , sc->sc_regs+0); |
| 396 | err |= __put_user(regs->r1 , sc->sc_regs+1); | 396 | err |= __put_user(regs->r1 , sc->sc_regs+1); |
| 397 | err |= __put_user(regs->r2 , sc->sc_regs+2); | 397 | err |= __put_user(regs->r2 , sc->sc_regs+2); |
| 398 | err |= __put_user(regs->r3 , sc->sc_regs+3); | 398 | err |= __put_user(regs->r3 , sc->sc_regs+3); |
| 399 | err |= __put_user(regs->r4 , sc->sc_regs+4); | 399 | err |= __put_user(regs->r4 , sc->sc_regs+4); |
| 400 | err |= __put_user(regs->r5 , sc->sc_regs+5); | 400 | err |= __put_user(regs->r5 , sc->sc_regs+5); |
| 401 | err |= __put_user(regs->r6 , sc->sc_regs+6); | 401 | err |= __put_user(regs->r6 , sc->sc_regs+6); |
| 402 | err |= __put_user(regs->r7 , sc->sc_regs+7); | 402 | err |= __put_user(regs->r7 , sc->sc_regs+7); |
| 403 | err |= __put_user(regs->r8 , sc->sc_regs+8); | 403 | err |= __put_user(regs->r8 , sc->sc_regs+8); |
| 404 | err |= __put_user(sw->r9 , sc->sc_regs+9); | 404 | err |= __put_user(sw->r9 , sc->sc_regs+9); |
| 405 | err |= __put_user(sw->r10 , sc->sc_regs+10); | 405 | err |= __put_user(sw->r10 , sc->sc_regs+10); |
| 406 | err |= __put_user(sw->r11 , sc->sc_regs+11); | 406 | err |= __put_user(sw->r11 , sc->sc_regs+11); |
| 407 | err |= __put_user(sw->r12 , sc->sc_regs+12); | 407 | err |= __put_user(sw->r12 , sc->sc_regs+12); |
| 408 | err |= __put_user(sw->r13 , sc->sc_regs+13); | 408 | err |= __put_user(sw->r13 , sc->sc_regs+13); |
| 409 | err |= __put_user(sw->r14 , sc->sc_regs+14); | 409 | err |= __put_user(sw->r14 , sc->sc_regs+14); |
| 410 | err |= __put_user(sw->r15 , sc->sc_regs+15); | 410 | err |= __put_user(sw->r15 , sc->sc_regs+15); |
| 411 | err |= __put_user(regs->r16, sc->sc_regs+16); | 411 | err |= __put_user(regs->r16, sc->sc_regs+16); |
| 412 | err |= __put_user(regs->r17, sc->sc_regs+17); | 412 | err |= __put_user(regs->r17, sc->sc_regs+17); |
| 413 | err |= __put_user(regs->r18, sc->sc_regs+18); | 413 | err |= __put_user(regs->r18, sc->sc_regs+18); |
| 414 | err |= __put_user(regs->r19, sc->sc_regs+19); | 414 | err |= __put_user(regs->r19, sc->sc_regs+19); |
| 415 | err |= __put_user(regs->r20, sc->sc_regs+20); | 415 | err |= __put_user(regs->r20, sc->sc_regs+20); |
| 416 | err |= __put_user(regs->r21, sc->sc_regs+21); | 416 | err |= __put_user(regs->r21, sc->sc_regs+21); |
| 417 | err |= __put_user(regs->r22, sc->sc_regs+22); | 417 | err |= __put_user(regs->r22, sc->sc_regs+22); |
| 418 | err |= __put_user(regs->r23, sc->sc_regs+23); | 418 | err |= __put_user(regs->r23, sc->sc_regs+23); |
| 419 | err |= __put_user(regs->r24, sc->sc_regs+24); | 419 | err |= __put_user(regs->r24, sc->sc_regs+24); |
| 420 | err |= __put_user(regs->r25, sc->sc_regs+25); | 420 | err |= __put_user(regs->r25, sc->sc_regs+25); |
| 421 | err |= __put_user(regs->r26, sc->sc_regs+26); | 421 | err |= __put_user(regs->r26, sc->sc_regs+26); |
| 422 | err |= __put_user(regs->r27, sc->sc_regs+27); | 422 | err |= __put_user(regs->r27, sc->sc_regs+27); |
| 423 | err |= __put_user(regs->r28, sc->sc_regs+28); | 423 | err |= __put_user(regs->r28, sc->sc_regs+28); |
| 424 | err |= __put_user(regs->gp , sc->sc_regs+29); | 424 | err |= __put_user(regs->gp , sc->sc_regs+29); |
| 425 | err |= __put_user(sp, sc->sc_regs+30); | 425 | err |= __put_user(sp, sc->sc_regs+30); |
| 426 | err |= __put_user(0, sc->sc_regs+31); | 426 | err |= __put_user(0, sc->sc_regs+31); |
| 427 | 427 | ||
| 428 | for (i = 0; i < 31; i++) | 428 | for (i = 0; i < 31; i++) |
| 429 | err |= __put_user(sw->fp[i], sc->sc_fpregs+i); | 429 | err |= __put_user(sw->fp[i], sc->sc_fpregs+i); |
| 430 | err |= __put_user(0, sc->sc_fpregs+31); | 430 | err |= __put_user(0, sc->sc_fpregs+31); |
| 431 | err |= __put_user(sw->fp[31], &sc->sc_fpcr); | 431 | err |= __put_user(sw->fp[31], &sc->sc_fpcr); |
| 432 | 432 | ||
| 433 | err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0); | 433 | err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0); |
| 434 | err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1); | 434 | err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1); |
| 435 | err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2); | 435 | err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2); |
| 436 | 436 | ||
| 437 | return err; | 437 | return err; |
| 438 | } | 438 | } |
| 439 | 439 | ||
| 440 | static void | 440 | static void |
| 441 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 441 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, |
| 442 | struct pt_regs *regs, struct switch_stack * sw) | 442 | struct pt_regs *regs, struct switch_stack * sw) |
| 443 | { | 443 | { |
| 444 | unsigned long oldsp, r26, err = 0; | 444 | unsigned long oldsp, r26, err = 0; |
| 445 | struct sigframe __user *frame; | 445 | struct sigframe __user *frame; |
| 446 | 446 | ||
| 447 | oldsp = rdusp(); | 447 | oldsp = rdusp(); |
| 448 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); | 448 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); |
| 449 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 449 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 450 | goto give_sigsegv; | 450 | goto give_sigsegv; |
| 451 | 451 | ||
| 452 | err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); | 452 | err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); |
| 453 | if (err) | 453 | if (err) |
| 454 | goto give_sigsegv; | 454 | goto give_sigsegv; |
| 455 | 455 | ||
| 456 | /* Set up to return from userspace. If provided, use a stub | 456 | /* Set up to return from userspace. If provided, use a stub |
| 457 | already in userspace. */ | 457 | already in userspace. */ |
| 458 | if (ka->ka_restorer) { | 458 | if (ka->ka_restorer) { |
| 459 | r26 = (unsigned long) ka->ka_restorer; | 459 | r26 = (unsigned long) ka->ka_restorer; |
| 460 | } else { | 460 | } else { |
| 461 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); | 461 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); |
| 462 | err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); | 462 | err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); |
| 463 | err |= __put_user(INSN_CALLSYS, frame->retcode+2); | 463 | err |= __put_user(INSN_CALLSYS, frame->retcode+2); |
| 464 | imb(); | 464 | imb(); |
| 465 | r26 = (unsigned long) frame->retcode; | 465 | r26 = (unsigned long) frame->retcode; |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | /* Check that everything was written properly. */ | 468 | /* Check that everything was written properly. */ |
| 469 | if (err) | 469 | if (err) |
| 470 | goto give_sigsegv; | 470 | goto give_sigsegv; |
| 471 | 471 | ||
| 472 | /* "Return" to the handler */ | 472 | /* "Return" to the handler */ |
| 473 | regs->r26 = r26; | 473 | regs->r26 = r26; |
| 474 | regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; | 474 | regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; |
| 475 | regs->r16 = sig; /* a0: signal number */ | 475 | regs->r16 = sig; /* a0: signal number */ |
| 476 | regs->r17 = 0; /* a1: exception code */ | 476 | regs->r17 = 0; /* a1: exception code */ |
| 477 | regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ | 477 | regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ |
| 478 | wrusp((unsigned long) frame); | 478 | wrusp((unsigned long) frame); |
| 479 | 479 | ||
| 480 | #if DEBUG_SIG | 480 | #if DEBUG_SIG |
| 481 | printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", | 481 | printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", |
| 482 | current->comm, current->pid, frame, regs->pc, regs->r26); | 482 | current->comm, current->pid, frame, regs->pc, regs->r26); |
| 483 | #endif | 483 | #endif |
| 484 | 484 | ||
| 485 | return; | 485 | return; |
| 486 | 486 | ||
| 487 | give_sigsegv: | 487 | give_sigsegv: |
| 488 | force_sigsegv(sig, current); | 488 | force_sigsegv(sig, current); |
| 489 | } | 489 | } |
| 490 | 490 | ||
| 491 | static void | 491 | static void |
| 492 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 492 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 493 | sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) | 493 | sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) |
| 494 | { | 494 | { |
| 495 | unsigned long oldsp, r26, err = 0; | 495 | unsigned long oldsp, r26, err = 0; |
| 496 | struct rt_sigframe __user *frame; | 496 | struct rt_sigframe __user *frame; |
| 497 | 497 | ||
| 498 | oldsp = rdusp(); | 498 | oldsp = rdusp(); |
| 499 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); | 499 | frame = get_sigframe(ka, oldsp, sizeof(*frame)); |
| 500 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 500 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 501 | goto give_sigsegv; | 501 | goto give_sigsegv; |
| 502 | 502 | ||
| 503 | err |= copy_siginfo_to_user(&frame->info, info); | 503 | err |= copy_siginfo_to_user(&frame->info, info); |
| 504 | 504 | ||
| 505 | /* Create the ucontext. */ | 505 | /* Create the ucontext. */ |
| 506 | err |= __put_user(0, &frame->uc.uc_flags); | 506 | err |= __put_user(0, &frame->uc.uc_flags); |
| 507 | err |= __put_user(0, &frame->uc.uc_link); | 507 | err |= __put_user(0, &frame->uc.uc_link); |
| 508 | err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); | 508 | err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); |
| 509 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 509 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
| 510 | err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags); | 510 | err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags); |
| 511 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 511 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
| 512 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, | 512 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, |
| 513 | set->sig[0], oldsp); | 513 | set->sig[0], oldsp); |
| 514 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 514 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 515 | if (err) | 515 | if (err) |
| 516 | goto give_sigsegv; | 516 | goto give_sigsegv; |
| 517 | 517 | ||
| 518 | /* Set up to return from userspace. If provided, use a stub | 518 | /* Set up to return from userspace. If provided, use a stub |
| 519 | already in userspace. */ | 519 | already in userspace. */ |
| 520 | if (ka->ka_restorer) { | 520 | if (ka->ka_restorer) { |
| 521 | r26 = (unsigned long) ka->ka_restorer; | 521 | r26 = (unsigned long) ka->ka_restorer; |
| 522 | } else { | 522 | } else { |
| 523 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); | 523 | err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); |
| 524 | err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn, | 524 | err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn, |
| 525 | frame->retcode+1); | 525 | frame->retcode+1); |
| 526 | err |= __put_user(INSN_CALLSYS, frame->retcode+2); | 526 | err |= __put_user(INSN_CALLSYS, frame->retcode+2); |
| 527 | imb(); | 527 | imb(); |
| 528 | r26 = (unsigned long) frame->retcode; | 528 | r26 = (unsigned long) frame->retcode; |
| 529 | } | 529 | } |
| 530 | 530 | ||
| 531 | if (err) | 531 | if (err) |
| 532 | goto give_sigsegv; | 532 | goto give_sigsegv; |
| 533 | 533 | ||
| 534 | /* "Return" to the handler */ | 534 | /* "Return" to the handler */ |
| 535 | regs->r26 = r26; | 535 | regs->r26 = r26; |
| 536 | regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; | 536 | regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; |
| 537 | regs->r16 = sig; /* a0: signal number */ | 537 | regs->r16 = sig; /* a0: signal number */ |
| 538 | regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */ | 538 | regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */ |
| 539 | regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */ | 539 | regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */ |
| 540 | wrusp((unsigned long) frame); | 540 | wrusp((unsigned long) frame); |
| 541 | 541 | ||
| 542 | #if DEBUG_SIG | 542 | #if DEBUG_SIG |
| 543 | printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", | 543 | printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", |
| 544 | current->comm, current->pid, frame, regs->pc, regs->r26); | 544 | current->comm, current->pid, frame, regs->pc, regs->r26); |
| 545 | #endif | 545 | #endif |
| 546 | 546 | ||
| 547 | return; | 547 | return; |
| 548 | 548 | ||
| 549 | give_sigsegv: | 549 | give_sigsegv: |
| 550 | force_sigsegv(sig, current); | 550 | force_sigsegv(sig, current); |
| 551 | } | 551 | } |
| 552 | 552 | ||
| 553 | 553 | ||
| 554 | /* | 554 | /* |
| 555 | * OK, we're invoking a handler. | 555 | * OK, we're invoking a handler. |
| 556 | */ | 556 | */ |
| 557 | static inline void | 557 | static inline void |
| 558 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | 558 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 559 | sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw) | 559 | sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw) |
| 560 | { | 560 | { |
| 561 | if (ka->sa.sa_flags & SA_SIGINFO) | 561 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 562 | setup_rt_frame(sig, ka, info, oldset, regs, sw); | 562 | setup_rt_frame(sig, ka, info, oldset, regs, sw); |
| 563 | else | 563 | else |
| 564 | setup_frame(sig, ka, oldset, regs, sw); | 564 | setup_frame(sig, ka, oldset, regs, sw); |
| 565 | 565 | ||
| 566 | if (ka->sa.sa_flags & SA_RESETHAND) | 566 | if (ka->sa.sa_flags & SA_RESETHAND) |
| 567 | ka->sa.sa_handler = SIG_DFL; | 567 | ka->sa.sa_handler = SIG_DFL; |
| 568 | 568 | ||
| 569 | spin_lock_irq(¤t->sighand->siglock); | 569 | spin_lock_irq(¤t->sighand->siglock); |
| 570 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 570 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
| 571 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 571 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 572 | sigaddset(¤t->blocked,sig); | 572 | sigaddset(¤t->blocked,sig); |
| 573 | recalc_sigpending(); | 573 | recalc_sigpending(); |
| 574 | spin_unlock_irq(¤t->sighand->siglock); | 574 | spin_unlock_irq(¤t->sighand->siglock); |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | static inline void | 577 | static inline void |
| 578 | syscall_restart(unsigned long r0, unsigned long r19, | 578 | syscall_restart(unsigned long r0, unsigned long r19, |
| 579 | struct pt_regs *regs, struct k_sigaction *ka) | 579 | struct pt_regs *regs, struct k_sigaction *ka) |
| 580 | { | 580 | { |
| 581 | switch (regs->r0) { | 581 | switch (regs->r0) { |
| 582 | case ERESTARTSYS: | 582 | case ERESTARTSYS: |
| 583 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 583 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
| 584 | case ERESTARTNOHAND: | 584 | case ERESTARTNOHAND: |
| 585 | regs->r0 = EINTR; | 585 | regs->r0 = EINTR; |
| 586 | break; | 586 | break; |
| 587 | } | 587 | } |
| 588 | /* fallthrough */ | 588 | /* fallthrough */ |
| 589 | case ERESTARTNOINTR: | 589 | case ERESTARTNOINTR: |
| 590 | regs->r0 = r0; /* reset v0 and a3 and replay syscall */ | 590 | regs->r0 = r0; /* reset v0 and a3 and replay syscall */ |
| 591 | regs->r19 = r19; | 591 | regs->r19 = r19; |
| 592 | regs->pc -= 4; | 592 | regs->pc -= 4; |
| 593 | break; | 593 | break; |
| 594 | case ERESTART_RESTARTBLOCK: | 594 | case ERESTART_RESTARTBLOCK: |
| 595 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 595 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
| 596 | regs->r0 = EINTR; | 596 | regs->r0 = EINTR; |
| 597 | break; | 597 | break; |
| 598 | } | 598 | } |
| 599 | } | 599 | } |
| 600 | 600 | ||
| 601 | 601 | ||
| 602 | /* | 602 | /* |
| 603 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 603 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 604 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 604 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 605 | * mistake. | 605 | * mistake. |
| 606 | * | 606 | * |
| 607 | * Note that we go through the signals twice: once to check the signals that | 607 | * Note that we go through the signals twice: once to check the signals that |
| 608 | * the kernel can handle, and then we build all the user-level signal handling | 608 | * the kernel can handle, and then we build all the user-level signal handling |
| 609 | * stack-frames in one go after that. | 609 | * stack-frames in one go after that. |
| 610 | * | 610 | * |
| 611 | * "r0" and "r19" are the registers we need to restore for system call | 611 | * "r0" and "r19" are the registers we need to restore for system call |
| 612 | * restart. "r0" is also used as an indicator whether we can restart at | 612 | * restart. "r0" is also used as an indicator whether we can restart at |
| 613 | * all (if we get here from anything but a syscall return, it will be 0) | 613 | * all (if we get here from anything but a syscall return, it will be 0) |
| 614 | */ | 614 | */ |
| 615 | static int | 615 | static int |
| 616 | do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw, | 616 | do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw, |
| 617 | unsigned long r0, unsigned long r19) | 617 | unsigned long r0, unsigned long r19) |
| 618 | { | 618 | { |
| 619 | siginfo_t info; | 619 | siginfo_t info; |
| 620 | int signr; | 620 | int signr; |
| 621 | unsigned long single_stepping = ptrace_cancel_bpt(current); | 621 | unsigned long single_stepping = ptrace_cancel_bpt(current); |
| 622 | struct k_sigaction ka; | 622 | struct k_sigaction ka; |
| 623 | 623 | ||
| 624 | if (!oldset) | 624 | if (!oldset) |
| 625 | oldset = ¤t->blocked; | 625 | oldset = ¤t->blocked; |
| 626 | 626 | ||
| 627 | /* This lets the debugger run, ... */ | 627 | /* This lets the debugger run, ... */ |
| 628 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 628 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 629 | /* ... so re-check the single stepping. */ | 629 | /* ... so re-check the single stepping. */ |
| 630 | single_stepping |= ptrace_cancel_bpt(current); | 630 | single_stepping |= ptrace_cancel_bpt(current); |
| 631 | 631 | ||
| 632 | if (signr > 0) { | 632 | if (signr > 0) { |
| 633 | /* Whee! Actually deliver the signal. */ | 633 | /* Whee! Actually deliver the signal. */ |
| 634 | if (r0) syscall_restart(r0, r19, regs, &ka); | 634 | if (r0) syscall_restart(r0, r19, regs, &ka); |
| 635 | handle_signal(signr, &ka, &info, oldset, regs, sw); | 635 | handle_signal(signr, &ka, &info, oldset, regs, sw); |
| 636 | if (single_stepping) | 636 | if (single_stepping) |
| 637 | ptrace_set_bpt(current); /* re-set bpt */ | 637 | ptrace_set_bpt(current); /* re-set bpt */ |
| 638 | return 1; | 638 | return 1; |
| 639 | } | 639 | } |
| 640 | 640 | ||
| 641 | if (r0) { | 641 | if (r0) { |
| 642 | switch (regs->r0) { | 642 | switch (regs->r0) { |
| 643 | case ERESTARTNOHAND: | 643 | case ERESTARTNOHAND: |
| 644 | case ERESTARTSYS: | 644 | case ERESTARTSYS: |
| 645 | case ERESTARTNOINTR: | 645 | case ERESTARTNOINTR: |
| 646 | /* Reset v0 and a3 and replay syscall. */ | 646 | /* Reset v0 and a3 and replay syscall. */ |
| 647 | regs->r0 = r0; | 647 | regs->r0 = r0; |
| 648 | regs->r19 = r19; | 648 | regs->r19 = r19; |
| 649 | regs->pc -= 4; | 649 | regs->pc -= 4; |
| 650 | break; | 650 | break; |
| 651 | case ERESTART_RESTARTBLOCK: | 651 | case ERESTART_RESTARTBLOCK: |
| 652 | /* Force v0 to the restart syscall and reply. */ | 652 | /* Force v0 to the restart syscall and reply. */ |
| 653 | regs->r0 = __NR_restart_syscall; | 653 | regs->r0 = __NR_restart_syscall; |
| 654 | regs->pc -= 4; | 654 | regs->pc -= 4; |
| 655 | break; | 655 | break; |
| 656 | } | 656 | } |
| 657 | } | 657 | } |
| 658 | if (single_stepping) | 658 | if (single_stepping) |
| 659 | ptrace_set_bpt(current); /* re-set breakpoint */ | 659 | ptrace_set_bpt(current); /* re-set breakpoint */ |
| 660 | 660 | ||
| 661 | return 0; | 661 | return 0; |
| 662 | } | 662 | } |
| 663 | 663 | ||
| 664 | void | 664 | void |
| 665 | do_notify_resume(sigset_t *oldset, struct pt_regs *regs, | 665 | do_notify_resume(sigset_t *oldset, struct pt_regs *regs, |
| 666 | struct switch_stack *sw, unsigned long r0, | 666 | struct switch_stack *sw, unsigned long r0, |
| 667 | unsigned long r19, unsigned long thread_info_flags) | 667 | unsigned long r19, unsigned long thread_info_flags) |
| 668 | { | 668 | { |
| 669 | if (thread_info_flags & _TIF_SIGPENDING) | 669 | if (thread_info_flags & _TIF_SIGPENDING) |
| 670 | do_signal(oldset, regs, sw, r0, r19); | 670 | do_signal(oldset, regs, sw, r0, r19); |
| 671 | } | 671 | } |
| 672 | 672 |
arch/frv/kernel/signal.c
| 1 | /* signal.c: FRV specific bits of signal handling | 1 | /* signal.c: FRV specific bits of signal handling |
| 2 | * | 2 | * |
| 3 | * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * - Derived from arch/m68k/kernel/signal.c | 5 | * - Derived from arch/m68k/kernel/signal.c |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
| 9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
| 10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
| 14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
| 15 | #include <linux/smp.h> | 15 | #include <linux/smp.h> |
| 16 | #include <linux/smp_lock.h> | 16 | #include <linux/smp_lock.h> |
| 17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 18 | #include <linux/signal.h> | 18 | #include <linux/signal.h> |
| 19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
| 20 | #include <linux/wait.h> | 20 | #include <linux/wait.h> |
| 21 | #include <linux/ptrace.h> | 21 | #include <linux/ptrace.h> |
| 22 | #include <linux/unistd.h> | 22 | #include <linux/unistd.h> |
| 23 | #include <linux/personality.h> | 23 | #include <linux/personality.h> |
| 24 | #include <linux/suspend.h> | 24 | #include <linux/suspend.h> |
| 25 | #include <asm/ucontext.h> | 25 | #include <asm/ucontext.h> |
| 26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
| 27 | #include <asm/cacheflush.h> | 27 | #include <asm/cacheflush.h> |
| 28 | 28 | ||
| 29 | #define DEBUG_SIG 0 | 29 | #define DEBUG_SIG 0 |
| 30 | 30 | ||
| 31 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 31 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 32 | 32 | ||
| 33 | struct fdpic_func_descriptor { | 33 | struct fdpic_func_descriptor { |
| 34 | unsigned long text; | 34 | unsigned long text; |
| 35 | unsigned long GOT; | 35 | unsigned long GOT; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | /* | 38 | /* |
| 39 | * Atomically swap in the new signal mask, and wait for a signal. | 39 | * Atomically swap in the new signal mask, and wait for a signal. |
| 40 | */ | 40 | */ |
| 41 | asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) | 41 | asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) |
| 42 | { | 42 | { |
| 43 | mask &= _BLOCKABLE; | 43 | mask &= _BLOCKABLE; |
| 44 | spin_lock_irq(¤t->sighand->siglock); | 44 | spin_lock_irq(¤t->sighand->siglock); |
| 45 | current->saved_sigmask = current->blocked; | 45 | current->saved_sigmask = current->blocked; |
| 46 | siginitset(¤t->blocked, mask); | 46 | siginitset(¤t->blocked, mask); |
| 47 | recalc_sigpending(); | 47 | recalc_sigpending(); |
| 48 | spin_unlock_irq(¤t->sighand->siglock); | 48 | spin_unlock_irq(¤t->sighand->siglock); |
| 49 | 49 | ||
| 50 | current->state = TASK_INTERRUPTIBLE; | 50 | current->state = TASK_INTERRUPTIBLE; |
| 51 | schedule(); | 51 | schedule(); |
| 52 | set_thread_flag(TIF_RESTORE_SIGMASK); | 52 | set_thread_flag(TIF_RESTORE_SIGMASK); |
| 53 | return -ERESTARTNOHAND; | 53 | return -ERESTARTNOHAND; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | asmlinkage int sys_sigaction(int sig, | 56 | asmlinkage int sys_sigaction(int sig, |
| 57 | const struct old_sigaction __user *act, | 57 | const struct old_sigaction __user *act, |
| 58 | struct old_sigaction __user *oact) | 58 | struct old_sigaction __user *oact) |
| 59 | { | 59 | { |
| 60 | struct k_sigaction new_ka, old_ka; | 60 | struct k_sigaction new_ka, old_ka; |
| 61 | int ret; | 61 | int ret; |
| 62 | 62 | ||
| 63 | if (act) { | 63 | if (act) { |
| 64 | old_sigset_t mask; | 64 | old_sigset_t mask; |
| 65 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 65 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
| 66 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 66 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
| 67 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 67 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) |
| 68 | return -EFAULT; | 68 | return -EFAULT; |
| 69 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | 69 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); |
| 70 | __get_user(mask, &act->sa_mask); | 70 | __get_user(mask, &act->sa_mask); |
| 71 | siginitset(&new_ka.sa.sa_mask, mask); | 71 | siginitset(&new_ka.sa.sa_mask, mask); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 74 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
| 75 | 75 | ||
| 76 | if (!ret && oact) { | 76 | if (!ret && oact) { |
| 77 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 77 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
| 78 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 78 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
| 79 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 79 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) |
| 80 | return -EFAULT; | 80 | return -EFAULT; |
| 81 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | 81 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
| 82 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | 82 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | return ret; | 85 | return ret; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | asmlinkage | 88 | asmlinkage |
| 89 | int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) | 89 | int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) |
| 90 | { | 90 | { |
| 91 | return do_sigaltstack(uss, uoss, __frame->sp); | 91 | return do_sigaltstack(uss, uoss, __frame->sp); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | 94 | ||
| 95 | /* | 95 | /* |
| 96 | * Do a signal return; undo the signal stack. | 96 | * Do a signal return; undo the signal stack. |
| 97 | */ | 97 | */ |
| 98 | 98 | ||
| 99 | struct sigframe | 99 | struct sigframe |
| 100 | { | 100 | { |
| 101 | __sigrestore_t pretcode; | 101 | __sigrestore_t pretcode; |
| 102 | int sig; | 102 | int sig; |
| 103 | struct sigcontext sc; | 103 | struct sigcontext sc; |
| 104 | unsigned long extramask[_NSIG_WORDS-1]; | 104 | unsigned long extramask[_NSIG_WORDS-1]; |
| 105 | uint32_t retcode[2]; | 105 | uint32_t retcode[2]; |
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| 108 | struct rt_sigframe | 108 | struct rt_sigframe |
| 109 | { | 109 | { |
| 110 | __sigrestore_t pretcode; | 110 | __sigrestore_t pretcode; |
| 111 | int sig; | 111 | int sig; |
| 112 | struct siginfo __user *pinfo; | 112 | struct siginfo __user *pinfo; |
| 113 | void __user *puc; | 113 | void __user *puc; |
| 114 | struct siginfo info; | 114 | struct siginfo info; |
| 115 | struct ucontext uc; | 115 | struct ucontext uc; |
| 116 | uint32_t retcode[2]; | 116 | uint32_t retcode[2]; |
| 117 | }; | 117 | }; |
| 118 | 118 | ||
| 119 | static int restore_sigcontext(struct sigcontext __user *sc, int *_gr8) | 119 | static int restore_sigcontext(struct sigcontext __user *sc, int *_gr8) |
| 120 | { | 120 | { |
| 121 | struct user_context *user = current->thread.user; | 121 | struct user_context *user = current->thread.user; |
| 122 | unsigned long tbr, psr; | 122 | unsigned long tbr, psr; |
| 123 | 123 | ||
| 124 | tbr = user->i.tbr; | 124 | tbr = user->i.tbr; |
| 125 | psr = user->i.psr; | 125 | psr = user->i.psr; |
| 126 | if (copy_from_user(user, &sc->sc_context, sizeof(sc->sc_context))) | 126 | if (copy_from_user(user, &sc->sc_context, sizeof(sc->sc_context))) |
| 127 | goto badframe; | 127 | goto badframe; |
| 128 | user->i.tbr = tbr; | 128 | user->i.tbr = tbr; |
| 129 | user->i.psr = psr; | 129 | user->i.psr = psr; |
| 130 | 130 | ||
| 131 | restore_user_regs(user); | 131 | restore_user_regs(user); |
| 132 | 132 | ||
| 133 | user->i.syscallno = -1; /* disable syscall checks */ | 133 | user->i.syscallno = -1; /* disable syscall checks */ |
| 134 | 134 | ||
| 135 | *_gr8 = user->i.gr[8]; | 135 | *_gr8 = user->i.gr[8]; |
| 136 | return 0; | 136 | return 0; |
| 137 | 137 | ||
| 138 | badframe: | 138 | badframe: |
| 139 | return 1; | 139 | return 1; |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | asmlinkage int sys_sigreturn(void) | 142 | asmlinkage int sys_sigreturn(void) |
| 143 | { | 143 | { |
| 144 | struct sigframe __user *frame = (struct sigframe __user *) __frame->sp; | 144 | struct sigframe __user *frame = (struct sigframe __user *) __frame->sp; |
| 145 | sigset_t set; | 145 | sigset_t set; |
| 146 | int gr8; | 146 | int gr8; |
| 147 | 147 | ||
| 148 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 148 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 149 | goto badframe; | 149 | goto badframe; |
| 150 | if (__get_user(set.sig[0], &frame->sc.sc_oldmask)) | 150 | if (__get_user(set.sig[0], &frame->sc.sc_oldmask)) |
| 151 | goto badframe; | 151 | goto badframe; |
| 152 | 152 | ||
| 153 | if (_NSIG_WORDS > 1 && | 153 | if (_NSIG_WORDS > 1 && |
| 154 | __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask))) | 154 | __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask))) |
| 155 | goto badframe; | 155 | goto badframe; |
| 156 | 156 | ||
| 157 | sigdelsetmask(&set, ~_BLOCKABLE); | 157 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 158 | spin_lock_irq(¤t->sighand->siglock); | 158 | spin_lock_irq(¤t->sighand->siglock); |
| 159 | current->blocked = set; | 159 | current->blocked = set; |
| 160 | recalc_sigpending(); | 160 | recalc_sigpending(); |
| 161 | spin_unlock_irq(¤t->sighand->siglock); | 161 | spin_unlock_irq(¤t->sighand->siglock); |
| 162 | 162 | ||
| 163 | if (restore_sigcontext(&frame->sc, &gr8)) | 163 | if (restore_sigcontext(&frame->sc, &gr8)) |
| 164 | goto badframe; | 164 | goto badframe; |
| 165 | return gr8; | 165 | return gr8; |
| 166 | 166 | ||
| 167 | badframe: | 167 | badframe: |
| 168 | force_sig(SIGSEGV, current); | 168 | force_sig(SIGSEGV, current); |
| 169 | return 0; | 169 | return 0; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | asmlinkage int sys_rt_sigreturn(void) | 172 | asmlinkage int sys_rt_sigreturn(void) |
| 173 | { | 173 | { |
| 174 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *) __frame->sp; | 174 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *) __frame->sp; |
| 175 | sigset_t set; | 175 | sigset_t set; |
| 176 | int gr8; | 176 | int gr8; |
| 177 | 177 | ||
| 178 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 178 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 179 | goto badframe; | 179 | goto badframe; |
| 180 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 180 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| 181 | goto badframe; | 181 | goto badframe; |
| 182 | 182 | ||
| 183 | sigdelsetmask(&set, ~_BLOCKABLE); | 183 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 184 | spin_lock_irq(¤t->sighand->siglock); | 184 | spin_lock_irq(¤t->sighand->siglock); |
| 185 | current->blocked = set; | 185 | current->blocked = set; |
| 186 | recalc_sigpending(); | 186 | recalc_sigpending(); |
| 187 | spin_unlock_irq(¤t->sighand->siglock); | 187 | spin_unlock_irq(¤t->sighand->siglock); |
| 188 | 188 | ||
| 189 | if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8)) | 189 | if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8)) |
| 190 | goto badframe; | 190 | goto badframe; |
| 191 | 191 | ||
| 192 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, __frame->sp) == -EFAULT) | 192 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, __frame->sp) == -EFAULT) |
| 193 | goto badframe; | 193 | goto badframe; |
| 194 | 194 | ||
| 195 | return gr8; | 195 | return gr8; |
| 196 | 196 | ||
| 197 | badframe: | 197 | badframe: |
| 198 | force_sig(SIGSEGV, current); | 198 | force_sig(SIGSEGV, current); |
| 199 | return 0; | 199 | return 0; |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | /* | 202 | /* |
| 203 | * Set up a signal frame | 203 | * Set up a signal frame |
| 204 | */ | 204 | */ |
| 205 | static int setup_sigcontext(struct sigcontext __user *sc, unsigned long mask) | 205 | static int setup_sigcontext(struct sigcontext __user *sc, unsigned long mask) |
| 206 | { | 206 | { |
| 207 | save_user_regs(current->thread.user); | 207 | save_user_regs(current->thread.user); |
| 208 | 208 | ||
| 209 | if (copy_to_user(&sc->sc_context, current->thread.user, sizeof(sc->sc_context)) != 0) | 209 | if (copy_to_user(&sc->sc_context, current->thread.user, sizeof(sc->sc_context)) != 0) |
| 210 | goto badframe; | 210 | goto badframe; |
| 211 | 211 | ||
| 212 | /* non-iBCS2 extensions.. */ | 212 | /* non-iBCS2 extensions.. */ |
| 213 | if (__put_user(mask, &sc->sc_oldmask) < 0) | 213 | if (__put_user(mask, &sc->sc_oldmask) < 0) |
| 214 | goto badframe; | 214 | goto badframe; |
| 215 | 215 | ||
| 216 | return 0; | 216 | return 0; |
| 217 | 217 | ||
| 218 | badframe: | 218 | badframe: |
| 219 | return 1; | 219 | return 1; |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | /*****************************************************************************/ | 222 | /*****************************************************************************/ |
| 223 | /* | 223 | /* |
| 224 | * Determine which stack to use.. | 224 | * Determine which stack to use.. |
| 225 | */ | 225 | */ |
| 226 | static inline void __user *get_sigframe(struct k_sigaction *ka, | 226 | static inline void __user *get_sigframe(struct k_sigaction *ka, |
| 227 | size_t frame_size) | 227 | size_t frame_size) |
| 228 | { | 228 | { |
| 229 | unsigned long sp; | 229 | unsigned long sp; |
| 230 | 230 | ||
| 231 | /* Default to using normal stack */ | 231 | /* Default to using normal stack */ |
| 232 | sp = __frame->sp; | 232 | sp = __frame->sp; |
| 233 | 233 | ||
| 234 | /* This is the X/Open sanctioned signal stack switching. */ | 234 | /* This is the X/Open sanctioned signal stack switching. */ |
| 235 | if (ka->sa.sa_flags & SA_ONSTACK) { | 235 | if (ka->sa.sa_flags & SA_ONSTACK) { |
| 236 | if (! on_sig_stack(sp)) | 236 | if (! sas_ss_flags(sp)) |
| 237 | sp = current->sas_ss_sp + current->sas_ss_size; | 237 | sp = current->sas_ss_sp + current->sas_ss_size; |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | return (void __user *) ((sp - frame_size) & ~7UL); | 240 | return (void __user *) ((sp - frame_size) & ~7UL); |
| 241 | 241 | ||
| 242 | } /* end get_sigframe() */ | 242 | } /* end get_sigframe() */ |
| 243 | 243 | ||
| 244 | /*****************************************************************************/ | 244 | /*****************************************************************************/ |
| 245 | /* | 245 | /* |
| 246 | * | 246 | * |
| 247 | */ | 247 | */ |
| 248 | static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) | 248 | static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) |
| 249 | { | 249 | { |
| 250 | struct sigframe __user *frame; | 250 | struct sigframe __user *frame; |
| 251 | int rsig; | 251 | int rsig; |
| 252 | 252 | ||
| 253 | frame = get_sigframe(ka, sizeof(*frame)); | 253 | frame = get_sigframe(ka, sizeof(*frame)); |
| 254 | 254 | ||
| 255 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 255 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 256 | goto give_sigsegv; | 256 | goto give_sigsegv; |
| 257 | 257 | ||
| 258 | rsig = sig; | 258 | rsig = sig; |
| 259 | if (sig < 32 && | 259 | if (sig < 32 && |
| 260 | __current_thread_info->exec_domain && | 260 | __current_thread_info->exec_domain && |
| 261 | __current_thread_info->exec_domain->signal_invmap) | 261 | __current_thread_info->exec_domain->signal_invmap) |
| 262 | rsig = __current_thread_info->exec_domain->signal_invmap[sig]; | 262 | rsig = __current_thread_info->exec_domain->signal_invmap[sig]; |
| 263 | 263 | ||
| 264 | if (__put_user(rsig, &frame->sig) < 0) | 264 | if (__put_user(rsig, &frame->sig) < 0) |
| 265 | goto give_sigsegv; | 265 | goto give_sigsegv; |
| 266 | 266 | ||
| 267 | if (setup_sigcontext(&frame->sc, set->sig[0])) | 267 | if (setup_sigcontext(&frame->sc, set->sig[0])) |
| 268 | goto give_sigsegv; | 268 | goto give_sigsegv; |
| 269 | 269 | ||
| 270 | if (_NSIG_WORDS > 1) { | 270 | if (_NSIG_WORDS > 1) { |
| 271 | if (__copy_to_user(frame->extramask, &set->sig[1], | 271 | if (__copy_to_user(frame->extramask, &set->sig[1], |
| 272 | sizeof(frame->extramask))) | 272 | sizeof(frame->extramask))) |
| 273 | goto give_sigsegv; | 273 | goto give_sigsegv; |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | /* Set up to return from userspace. If provided, use a stub | 276 | /* Set up to return from userspace. If provided, use a stub |
| 277 | * already in userspace. */ | 277 | * already in userspace. */ |
| 278 | if (ka->sa.sa_flags & SA_RESTORER) { | 278 | if (ka->sa.sa_flags & SA_RESTORER) { |
| 279 | if (__put_user(ka->sa.sa_restorer, &frame->pretcode) < 0) | 279 | if (__put_user(ka->sa.sa_restorer, &frame->pretcode) < 0) |
| 280 | goto give_sigsegv; | 280 | goto give_sigsegv; |
| 281 | } | 281 | } |
| 282 | else { | 282 | else { |
| 283 | /* Set up the following code on the stack: | 283 | /* Set up the following code on the stack: |
| 284 | * setlos #__NR_sigreturn,gr7 | 284 | * setlos #__NR_sigreturn,gr7 |
| 285 | * tira gr0,0 | 285 | * tira gr0,0 |
| 286 | */ | 286 | */ |
| 287 | if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) || | 287 | if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) || |
| 288 | __put_user(0x8efc0000|__NR_sigreturn, &frame->retcode[0]) || | 288 | __put_user(0x8efc0000|__NR_sigreturn, &frame->retcode[0]) || |
| 289 | __put_user(0xc0700000, &frame->retcode[1])) | 289 | __put_user(0xc0700000, &frame->retcode[1])) |
| 290 | goto give_sigsegv; | 290 | goto give_sigsegv; |
| 291 | 291 | ||
| 292 | flush_icache_range((unsigned long) frame->retcode, | 292 | flush_icache_range((unsigned long) frame->retcode, |
| 293 | (unsigned long) (frame->retcode + 2)); | 293 | (unsigned long) (frame->retcode + 2)); |
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | /* set up registers for signal handler */ | 296 | /* set up registers for signal handler */ |
| 297 | __frame->sp = (unsigned long) frame; | 297 | __frame->sp = (unsigned long) frame; |
| 298 | __frame->lr = (unsigned long) &frame->retcode; | 298 | __frame->lr = (unsigned long) &frame->retcode; |
| 299 | __frame->gr8 = sig; | 299 | __frame->gr8 = sig; |
| 300 | 300 | ||
| 301 | if (get_personality & FDPIC_FUNCPTRS) { | 301 | if (get_personality & FDPIC_FUNCPTRS) { |
| 302 | struct fdpic_func_descriptor __user *funcptr = | 302 | struct fdpic_func_descriptor __user *funcptr = |
| 303 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; | 303 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; |
| 304 | __get_user(__frame->pc, &funcptr->text); | 304 | __get_user(__frame->pc, &funcptr->text); |
| 305 | __get_user(__frame->gr15, &funcptr->GOT); | 305 | __get_user(__frame->gr15, &funcptr->GOT); |
| 306 | } else { | 306 | } else { |
| 307 | __frame->pc = (unsigned long) ka->sa.sa_handler; | 307 | __frame->pc = (unsigned long) ka->sa.sa_handler; |
| 308 | __frame->gr15 = 0; | 308 | __frame->gr15 = 0; |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | set_fs(USER_DS); | 311 | set_fs(USER_DS); |
| 312 | 312 | ||
| 313 | /* the tracer may want to single-step inside the handler */ | 313 | /* the tracer may want to single-step inside the handler */ |
| 314 | if (test_thread_flag(TIF_SINGLESTEP)) | 314 | if (test_thread_flag(TIF_SINGLESTEP)) |
| 315 | ptrace_notify(SIGTRAP); | 315 | ptrace_notify(SIGTRAP); |
| 316 | 316 | ||
| 317 | #if DEBUG_SIG | 317 | #if DEBUG_SIG |
| 318 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", | 318 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", |
| 319 | sig, current->comm, current->pid, frame, __frame->pc, | 319 | sig, current->comm, current->pid, frame, __frame->pc, |
| 320 | frame->pretcode); | 320 | frame->pretcode); |
| 321 | #endif | 321 | #endif |
| 322 | 322 | ||
| 323 | return 0; | 323 | return 0; |
| 324 | 324 | ||
| 325 | give_sigsegv: | 325 | give_sigsegv: |
| 326 | force_sig(SIGSEGV, current); | 326 | force_sig(SIGSEGV, current); |
| 327 | return -EFAULT; | 327 | return -EFAULT; |
| 328 | 328 | ||
| 329 | } /* end setup_frame() */ | 329 | } /* end setup_frame() */ |
| 330 | 330 | ||
| 331 | /*****************************************************************************/ | 331 | /*****************************************************************************/ |
| 332 | /* | 332 | /* |
| 333 | * | 333 | * |
| 334 | */ | 334 | */ |
| 335 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 335 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 336 | sigset_t *set) | 336 | sigset_t *set) |
| 337 | { | 337 | { |
| 338 | struct rt_sigframe __user *frame; | 338 | struct rt_sigframe __user *frame; |
| 339 | int rsig; | 339 | int rsig; |
| 340 | 340 | ||
| 341 | frame = get_sigframe(ka, sizeof(*frame)); | 341 | frame = get_sigframe(ka, sizeof(*frame)); |
| 342 | 342 | ||
| 343 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 343 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 344 | goto give_sigsegv; | 344 | goto give_sigsegv; |
| 345 | 345 | ||
| 346 | rsig = sig; | 346 | rsig = sig; |
| 347 | if (sig < 32 && | 347 | if (sig < 32 && |
| 348 | __current_thread_info->exec_domain && | 348 | __current_thread_info->exec_domain && |
| 349 | __current_thread_info->exec_domain->signal_invmap) | 349 | __current_thread_info->exec_domain->signal_invmap) |
| 350 | rsig = __current_thread_info->exec_domain->signal_invmap[sig]; | 350 | rsig = __current_thread_info->exec_domain->signal_invmap[sig]; |
| 351 | 351 | ||
| 352 | if (__put_user(rsig, &frame->sig) || | 352 | if (__put_user(rsig, &frame->sig) || |
| 353 | __put_user(&frame->info, &frame->pinfo) || | 353 | __put_user(&frame->info, &frame->pinfo) || |
| 354 | __put_user(&frame->uc, &frame->puc)) | 354 | __put_user(&frame->uc, &frame->puc)) |
| 355 | goto give_sigsegv; | 355 | goto give_sigsegv; |
| 356 | 356 | ||
| 357 | if (copy_siginfo_to_user(&frame->info, info)) | 357 | if (copy_siginfo_to_user(&frame->info, info)) |
| 358 | goto give_sigsegv; | 358 | goto give_sigsegv; |
| 359 | 359 | ||
| 360 | /* Create the ucontext. */ | 360 | /* Create the ucontext. */ |
| 361 | if (__put_user(0, &frame->uc.uc_flags) || | 361 | if (__put_user(0, &frame->uc.uc_flags) || |
| 362 | __put_user(NULL, &frame->uc.uc_link) || | 362 | __put_user(NULL, &frame->uc.uc_link) || |
| 363 | __put_user((void __user *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) || | 363 | __put_user((void __user *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) || |
| 364 | __put_user(sas_ss_flags(__frame->sp), &frame->uc.uc_stack.ss_flags) || | 364 | __put_user(sas_ss_flags(__frame->sp), &frame->uc.uc_stack.ss_flags) || |
| 365 | __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size)) | 365 | __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size)) |
| 366 | goto give_sigsegv; | 366 | goto give_sigsegv; |
| 367 | 367 | ||
| 368 | if (setup_sigcontext(&frame->uc.uc_mcontext, set->sig[0])) | 368 | if (setup_sigcontext(&frame->uc.uc_mcontext, set->sig[0])) |
| 369 | goto give_sigsegv; | 369 | goto give_sigsegv; |
| 370 | 370 | ||
| 371 | if (__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set))) | 371 | if (__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set))) |
| 372 | goto give_sigsegv; | 372 | goto give_sigsegv; |
| 373 | 373 | ||
| 374 | /* Set up to return from userspace. If provided, use a stub | 374 | /* Set up to return from userspace. If provided, use a stub |
| 375 | * already in userspace. */ | 375 | * already in userspace. */ |
| 376 | if (ka->sa.sa_flags & SA_RESTORER) { | 376 | if (ka->sa.sa_flags & SA_RESTORER) { |
| 377 | if (__put_user(ka->sa.sa_restorer, &frame->pretcode)) | 377 | if (__put_user(ka->sa.sa_restorer, &frame->pretcode)) |
| 378 | goto give_sigsegv; | 378 | goto give_sigsegv; |
| 379 | } | 379 | } |
| 380 | else { | 380 | else { |
| 381 | /* Set up the following code on the stack: | 381 | /* Set up the following code on the stack: |
| 382 | * setlos #__NR_sigreturn,gr7 | 382 | * setlos #__NR_sigreturn,gr7 |
| 383 | * tira gr0,0 | 383 | * tira gr0,0 |
| 384 | */ | 384 | */ |
| 385 | if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) || | 385 | if (__put_user((__sigrestore_t)frame->retcode, &frame->pretcode) || |
| 386 | __put_user(0x8efc0000|__NR_rt_sigreturn, &frame->retcode[0]) || | 386 | __put_user(0x8efc0000|__NR_rt_sigreturn, &frame->retcode[0]) || |
| 387 | __put_user(0xc0700000, &frame->retcode[1])) | 387 | __put_user(0xc0700000, &frame->retcode[1])) |
| 388 | goto give_sigsegv; | 388 | goto give_sigsegv; |
| 389 | 389 | ||
| 390 | flush_icache_range((unsigned long) frame->retcode, | 390 | flush_icache_range((unsigned long) frame->retcode, |
| 391 | (unsigned long) (frame->retcode + 2)); | 391 | (unsigned long) (frame->retcode + 2)); |
| 392 | } | 392 | } |
| 393 | 393 | ||
| 394 | /* Set up registers for signal handler */ | 394 | /* Set up registers for signal handler */ |
| 395 | __frame->sp = (unsigned long) frame; | 395 | __frame->sp = (unsigned long) frame; |
| 396 | __frame->lr = (unsigned long) &frame->retcode; | 396 | __frame->lr = (unsigned long) &frame->retcode; |
| 397 | __frame->gr8 = sig; | 397 | __frame->gr8 = sig; |
| 398 | __frame->gr9 = (unsigned long) &frame->info; | 398 | __frame->gr9 = (unsigned long) &frame->info; |
| 399 | 399 | ||
| 400 | if (get_personality & FDPIC_FUNCPTRS) { | 400 | if (get_personality & FDPIC_FUNCPTRS) { |
| 401 | struct fdpic_func_descriptor __user *funcptr = | 401 | struct fdpic_func_descriptor __user *funcptr = |
| 402 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; | 402 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; |
| 403 | __get_user(__frame->pc, &funcptr->text); | 403 | __get_user(__frame->pc, &funcptr->text); |
| 404 | __get_user(__frame->gr15, &funcptr->GOT); | 404 | __get_user(__frame->gr15, &funcptr->GOT); |
| 405 | } else { | 405 | } else { |
| 406 | __frame->pc = (unsigned long) ka->sa.sa_handler; | 406 | __frame->pc = (unsigned long) ka->sa.sa_handler; |
| 407 | __frame->gr15 = 0; | 407 | __frame->gr15 = 0; |
| 408 | } | 408 | } |
| 409 | 409 | ||
| 410 | set_fs(USER_DS); | 410 | set_fs(USER_DS); |
| 411 | 411 | ||
| 412 | /* the tracer may want to single-step inside the handler */ | 412 | /* the tracer may want to single-step inside the handler */ |
| 413 | if (test_thread_flag(TIF_SINGLESTEP)) | 413 | if (test_thread_flag(TIF_SINGLESTEP)) |
| 414 | ptrace_notify(SIGTRAP); | 414 | ptrace_notify(SIGTRAP); |
| 415 | 415 | ||
| 416 | #if DEBUG_SIG | 416 | #if DEBUG_SIG |
| 417 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", | 417 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", |
| 418 | sig, current->comm, current->pid, frame, __frame->pc, | 418 | sig, current->comm, current->pid, frame, __frame->pc, |
| 419 | frame->pretcode); | 419 | frame->pretcode); |
| 420 | #endif | 420 | #endif |
| 421 | 421 | ||
| 422 | return 0; | 422 | return 0; |
| 423 | 423 | ||
| 424 | give_sigsegv: | 424 | give_sigsegv: |
| 425 | force_sig(SIGSEGV, current); | 425 | force_sig(SIGSEGV, current); |
| 426 | return -EFAULT; | 426 | return -EFAULT; |
| 427 | 427 | ||
| 428 | } /* end setup_rt_frame() */ | 428 | } /* end setup_rt_frame() */ |
| 429 | 429 | ||
| 430 | /*****************************************************************************/ | 430 | /*****************************************************************************/ |
| 431 | /* | 431 | /* |
| 432 | * OK, we're invoking a handler | 432 | * OK, we're invoking a handler |
| 433 | */ | 433 | */ |
| 434 | static int handle_signal(unsigned long sig, siginfo_t *info, | 434 | static int handle_signal(unsigned long sig, siginfo_t *info, |
| 435 | struct k_sigaction *ka, sigset_t *oldset) | 435 | struct k_sigaction *ka, sigset_t *oldset) |
| 436 | { | 436 | { |
| 437 | int ret; | 437 | int ret; |
| 438 | 438 | ||
| 439 | /* Are we from a system call? */ | 439 | /* Are we from a system call? */ |
| 440 | if (in_syscall(__frame)) { | 440 | if (in_syscall(__frame)) { |
| 441 | /* If so, check system call restarting.. */ | 441 | /* If so, check system call restarting.. */ |
| 442 | switch (__frame->gr8) { | 442 | switch (__frame->gr8) { |
| 443 | case -ERESTART_RESTARTBLOCK: | 443 | case -ERESTART_RESTARTBLOCK: |
| 444 | case -ERESTARTNOHAND: | 444 | case -ERESTARTNOHAND: |
| 445 | __frame->gr8 = -EINTR; | 445 | __frame->gr8 = -EINTR; |
| 446 | break; | 446 | break; |
| 447 | 447 | ||
| 448 | case -ERESTARTSYS: | 448 | case -ERESTARTSYS: |
| 449 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 449 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
| 450 | __frame->gr8 = -EINTR; | 450 | __frame->gr8 = -EINTR; |
| 451 | break; | 451 | break; |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | /* fallthrough */ | 454 | /* fallthrough */ |
| 455 | case -ERESTARTNOINTR: | 455 | case -ERESTARTNOINTR: |
| 456 | __frame->gr8 = __frame->orig_gr8; | 456 | __frame->gr8 = __frame->orig_gr8; |
| 457 | __frame->pc -= 4; | 457 | __frame->pc -= 4; |
| 458 | } | 458 | } |
| 459 | } | 459 | } |
| 460 | 460 | ||
| 461 | /* Set up the stack frame */ | 461 | /* Set up the stack frame */ |
| 462 | if (ka->sa.sa_flags & SA_SIGINFO) | 462 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 463 | ret = setup_rt_frame(sig, ka, info, oldset); | 463 | ret = setup_rt_frame(sig, ka, info, oldset); |
| 464 | else | 464 | else |
| 465 | ret = setup_frame(sig, ka, oldset); | 465 | ret = setup_frame(sig, ka, oldset); |
| 466 | 466 | ||
| 467 | if (ret == 0) { | 467 | if (ret == 0) { |
| 468 | spin_lock_irq(¤t->sighand->siglock); | 468 | spin_lock_irq(¤t->sighand->siglock); |
| 469 | sigorsets(¤t->blocked, ¤t->blocked, | 469 | sigorsets(¤t->blocked, ¤t->blocked, |
| 470 | &ka->sa.sa_mask); | 470 | &ka->sa.sa_mask); |
| 471 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 471 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 472 | sigaddset(¤t->blocked, sig); | 472 | sigaddset(¤t->blocked, sig); |
| 473 | recalc_sigpending(); | 473 | recalc_sigpending(); |
| 474 | spin_unlock_irq(¤t->sighand->siglock); | 474 | spin_unlock_irq(¤t->sighand->siglock); |
| 475 | } | 475 | } |
| 476 | 476 | ||
| 477 | return ret; | 477 | return ret; |
| 478 | 478 | ||
| 479 | } /* end handle_signal() */ | 479 | } /* end handle_signal() */ |
| 480 | 480 | ||
| 481 | /*****************************************************************************/ | 481 | /*****************************************************************************/ |
| 482 | /* | 482 | /* |
| 483 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 483 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 484 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 484 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 485 | * mistake. | 485 | * mistake. |
| 486 | */ | 486 | */ |
| 487 | static void do_signal(void) | 487 | static void do_signal(void) |
| 488 | { | 488 | { |
| 489 | struct k_sigaction ka; | 489 | struct k_sigaction ka; |
| 490 | siginfo_t info; | 490 | siginfo_t info; |
| 491 | sigset_t *oldset; | 491 | sigset_t *oldset; |
| 492 | int signr; | 492 | int signr; |
| 493 | 493 | ||
| 494 | /* | 494 | /* |
| 495 | * We want the common case to go fast, which | 495 | * We want the common case to go fast, which |
| 496 | * is why we may in certain cases get here from | 496 | * is why we may in certain cases get here from |
| 497 | * kernel mode. Just return without doing anything | 497 | * kernel mode. Just return without doing anything |
| 498 | * if so. | 498 | * if so. |
| 499 | */ | 499 | */ |
| 500 | if (!user_mode(__frame)) | 500 | if (!user_mode(__frame)) |
| 501 | return; | 501 | return; |
| 502 | 502 | ||
| 503 | if (try_to_freeze()) | 503 | if (try_to_freeze()) |
| 504 | goto no_signal; | 504 | goto no_signal; |
| 505 | 505 | ||
| 506 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 506 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
| 507 | oldset = ¤t->saved_sigmask; | 507 | oldset = ¤t->saved_sigmask; |
| 508 | else | 508 | else |
| 509 | oldset = ¤t->blocked; | 509 | oldset = ¤t->blocked; |
| 510 | 510 | ||
| 511 | signr = get_signal_to_deliver(&info, &ka, __frame, NULL); | 511 | signr = get_signal_to_deliver(&info, &ka, __frame, NULL); |
| 512 | if (signr > 0) { | 512 | if (signr > 0) { |
| 513 | if (handle_signal(signr, &info, &ka, oldset) == 0) { | 513 | if (handle_signal(signr, &info, &ka, oldset) == 0) { |
| 514 | /* a signal was successfully delivered; the saved | 514 | /* a signal was successfully delivered; the saved |
| 515 | * sigmask will have been stored in the signal frame, | 515 | * sigmask will have been stored in the signal frame, |
| 516 | * and will be restored by sigreturn, so we can simply | 516 | * and will be restored by sigreturn, so we can simply |
| 517 | * clear the TIF_RESTORE_SIGMASK flag */ | 517 | * clear the TIF_RESTORE_SIGMASK flag */ |
| 518 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 518 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
| 519 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 519 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | return; | 522 | return; |
| 523 | } | 523 | } |
| 524 | 524 | ||
| 525 | no_signal: | 525 | no_signal: |
| 526 | /* Did we come from a system call? */ | 526 | /* Did we come from a system call? */ |
| 527 | if (__frame->syscallno >= 0) { | 527 | if (__frame->syscallno >= 0) { |
| 528 | /* Restart the system call - no handlers present */ | 528 | /* Restart the system call - no handlers present */ |
| 529 | switch (__frame->gr8) { | 529 | switch (__frame->gr8) { |
| 530 | case -ERESTARTNOHAND: | 530 | case -ERESTARTNOHAND: |
| 531 | case -ERESTARTSYS: | 531 | case -ERESTARTSYS: |
| 532 | case -ERESTARTNOINTR: | 532 | case -ERESTARTNOINTR: |
| 533 | __frame->gr8 = __frame->orig_gr8; | 533 | __frame->gr8 = __frame->orig_gr8; |
| 534 | __frame->pc -= 4; | 534 | __frame->pc -= 4; |
| 535 | break; | 535 | break; |
| 536 | 536 | ||
| 537 | case -ERESTART_RESTARTBLOCK: | 537 | case -ERESTART_RESTARTBLOCK: |
| 538 | __frame->gr8 = __NR_restart_syscall; | 538 | __frame->gr8 = __NR_restart_syscall; |
| 539 | __frame->pc -= 4; | 539 | __frame->pc -= 4; |
| 540 | break; | 540 | break; |
| 541 | } | 541 | } |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | /* if there's no signal to deliver, we just put the saved sigmask | 544 | /* if there's no signal to deliver, we just put the saved sigmask |
| 545 | * back */ | 545 | * back */ |
| 546 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | 546 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { |
| 547 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 547 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
| 548 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 548 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
| 549 | } | 549 | } |
| 550 | 550 | ||
| 551 | } /* end do_signal() */ | 551 | } /* end do_signal() */ |
| 552 | 552 | ||
| 553 | /*****************************************************************************/ | 553 | /*****************************************************************************/ |
| 554 | /* | 554 | /* |
| 555 | * notification of userspace execution resumption | 555 | * notification of userspace execution resumption |
| 556 | * - triggered by the TIF_WORK_MASK flags | 556 | * - triggered by the TIF_WORK_MASK flags |
| 557 | */ | 557 | */ |
| 558 | asmlinkage void do_notify_resume(__u32 thread_info_flags) | 558 | asmlinkage void do_notify_resume(__u32 thread_info_flags) |
| 559 | { | 559 | { |
| 560 | /* pending single-step? */ | 560 | /* pending single-step? */ |
| 561 | if (thread_info_flags & _TIF_SINGLESTEP) | 561 | if (thread_info_flags & _TIF_SINGLESTEP) |
| 562 | clear_thread_flag(TIF_SINGLESTEP); | 562 | clear_thread_flag(TIF_SINGLESTEP); |
| 563 | 563 | ||
| 564 | /* deal with pending signal delivery */ | 564 | /* deal with pending signal delivery */ |
| 565 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) | 565 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
| 566 | do_signal(); | 566 | do_signal(); |
| 567 | 567 | ||
| 568 | } /* end do_notify_resume() */ | 568 | } /* end do_notify_resume() */ |
| 569 | 569 |
arch/h8300/kernel/signal.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/h8300/kernel/signal.c | 2 | * linux/arch/h8300/kernel/signal.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1991, 1992 Linus Torvalds | 4 | * Copyright (C) 1991, 1992 Linus Torvalds |
| 5 | * | 5 | * |
| 6 | * This file is subject to the terms and conditions of the GNU General Public | 6 | * This file is subject to the terms and conditions of the GNU General Public |
| 7 | * License. See the file COPYING in the main directory of this archive | 7 | * License. See the file COPYING in the main directory of this archive |
| 8 | * for more details. | 8 | * for more details. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | /* | 11 | /* |
| 12 | * uClinux H8/300 support by Yoshinori Sato <ysato@users.sourceforge.jp> | 12 | * uClinux H8/300 support by Yoshinori Sato <ysato@users.sourceforge.jp> |
| 13 | * and David McCullough <davidm@snapgear.com> | 13 | * and David McCullough <davidm@snapgear.com> |
| 14 | * | 14 | * |
| 15 | * Based on | 15 | * Based on |
| 16 | * Linux/m68k by Hamish Macdonald | 16 | * Linux/m68k by Hamish Macdonald |
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | /* | 19 | /* |
| 20 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on | 20 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on |
| 21 | * Atari :-) Current limitation: Only one sigstack can be active at one time. | 21 | * Atari :-) Current limitation: Only one sigstack can be active at one time. |
| 22 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, | 22 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, |
| 23 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested | 23 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested |
| 24 | * signal handlers! | 24 | * signal handlers! |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
| 28 | #include <linux/mm.h> | 28 | #include <linux/mm.h> |
| 29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
| 30 | #include <linux/signal.h> | 30 | #include <linux/signal.h> |
| 31 | #include <linux/syscalls.h> | 31 | #include <linux/syscalls.h> |
| 32 | #include <linux/errno.h> | 32 | #include <linux/errno.h> |
| 33 | #include <linux/wait.h> | 33 | #include <linux/wait.h> |
| 34 | #include <linux/ptrace.h> | 34 | #include <linux/ptrace.h> |
| 35 | #include <linux/unistd.h> | 35 | #include <linux/unistd.h> |
| 36 | #include <linux/stddef.h> | 36 | #include <linux/stddef.h> |
| 37 | #include <linux/highuid.h> | 37 | #include <linux/highuid.h> |
| 38 | #include <linux/personality.h> | 38 | #include <linux/personality.h> |
| 39 | #include <linux/tty.h> | 39 | #include <linux/tty.h> |
| 40 | #include <linux/binfmts.h> | 40 | #include <linux/binfmts.h> |
| 41 | #include <linux/suspend.h> | 41 | #include <linux/suspend.h> |
| 42 | 42 | ||
| 43 | #include <asm/setup.h> | 43 | #include <asm/setup.h> |
| 44 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
| 45 | #include <asm/pgtable.h> | 45 | #include <asm/pgtable.h> |
| 46 | #include <asm/traps.h> | 46 | #include <asm/traps.h> |
| 47 | #include <asm/ucontext.h> | 47 | #include <asm/ucontext.h> |
| 48 | 48 | ||
| 49 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 49 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 50 | 50 | ||
| 51 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | 51 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); |
| 52 | 52 | ||
| 53 | /* | 53 | /* |
| 54 | * Atomically swap in the new signal mask, and wait for a signal. | 54 | * Atomically swap in the new signal mask, and wait for a signal. |
| 55 | */ | 55 | */ |
| 56 | asmlinkage int do_sigsuspend(struct pt_regs *regs) | 56 | asmlinkage int do_sigsuspend(struct pt_regs *regs) |
| 57 | { | 57 | { |
| 58 | old_sigset_t mask = regs->er3; | 58 | old_sigset_t mask = regs->er3; |
| 59 | sigset_t saveset; | 59 | sigset_t saveset; |
| 60 | 60 | ||
| 61 | mask &= _BLOCKABLE; | 61 | mask &= _BLOCKABLE; |
| 62 | spin_lock_irq(¤t->sighand->siglock); | 62 | spin_lock_irq(¤t->sighand->siglock); |
| 63 | saveset = current->blocked; | 63 | saveset = current->blocked; |
| 64 | siginitset(¤t->blocked, mask); | 64 | siginitset(¤t->blocked, mask); |
| 65 | recalc_sigpending(); | 65 | recalc_sigpending(); |
| 66 | spin_unlock_irq(¤t->sighand->siglock); | 66 | spin_unlock_irq(¤t->sighand->siglock); |
| 67 | 67 | ||
| 68 | regs->er0 = -EINTR; | 68 | regs->er0 = -EINTR; |
| 69 | while (1) { | 69 | while (1) { |
| 70 | current->state = TASK_INTERRUPTIBLE; | 70 | current->state = TASK_INTERRUPTIBLE; |
| 71 | schedule(); | 71 | schedule(); |
| 72 | if (do_signal(regs, &saveset)) | 72 | if (do_signal(regs, &saveset)) |
| 73 | return -EINTR; | 73 | return -EINTR; |
| 74 | } | 74 | } |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | asmlinkage int | 77 | asmlinkage int |
| 78 | do_rt_sigsuspend(struct pt_regs *regs) | 78 | do_rt_sigsuspend(struct pt_regs *regs) |
| 79 | { | 79 | { |
| 80 | sigset_t *unewset = (sigset_t *)regs->er1; | 80 | sigset_t *unewset = (sigset_t *)regs->er1; |
| 81 | size_t sigsetsize = (size_t)regs->er2; | 81 | size_t sigsetsize = (size_t)regs->er2; |
| 82 | sigset_t saveset, newset; | 82 | sigset_t saveset, newset; |
| 83 | 83 | ||
| 84 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 84 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
| 85 | if (sigsetsize != sizeof(sigset_t)) | 85 | if (sigsetsize != sizeof(sigset_t)) |
| 86 | return -EINVAL; | 86 | return -EINVAL; |
| 87 | 87 | ||
| 88 | if (copy_from_user(&newset, unewset, sizeof(newset))) | 88 | if (copy_from_user(&newset, unewset, sizeof(newset))) |
| 89 | return -EFAULT; | 89 | return -EFAULT; |
| 90 | sigdelsetmask(&newset, ~_BLOCKABLE); | 90 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 91 | 91 | ||
| 92 | spin_lock_irq(¤t->sighand->siglock); | 92 | spin_lock_irq(¤t->sighand->siglock); |
| 93 | saveset = current->blocked; | 93 | saveset = current->blocked; |
| 94 | current->blocked = newset; | 94 | current->blocked = newset; |
| 95 | recalc_sigpending(); | 95 | recalc_sigpending(); |
| 96 | spin_unlock_irq(¤t->sighand->siglock); | 96 | spin_unlock_irq(¤t->sighand->siglock); |
| 97 | 97 | ||
| 98 | regs->er0 = -EINTR; | 98 | regs->er0 = -EINTR; |
| 99 | while (1) { | 99 | while (1) { |
| 100 | current->state = TASK_INTERRUPTIBLE; | 100 | current->state = TASK_INTERRUPTIBLE; |
| 101 | schedule(); | 101 | schedule(); |
| 102 | if (do_signal(regs, &saveset)) | 102 | if (do_signal(regs, &saveset)) |
| 103 | return -EINTR; | 103 | return -EINTR; |
| 104 | } | 104 | } |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | asmlinkage int | 107 | asmlinkage int |
| 108 | sys_sigaction(int sig, const struct old_sigaction *act, | 108 | sys_sigaction(int sig, const struct old_sigaction *act, |
| 109 | struct old_sigaction *oact) | 109 | struct old_sigaction *oact) |
| 110 | { | 110 | { |
| 111 | struct k_sigaction new_ka, old_ka; | 111 | struct k_sigaction new_ka, old_ka; |
| 112 | int ret; | 112 | int ret; |
| 113 | 113 | ||
| 114 | if (act) { | 114 | if (act) { |
| 115 | old_sigset_t mask; | 115 | old_sigset_t mask; |
| 116 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 116 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
| 117 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 117 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
| 118 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 118 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) |
| 119 | return -EFAULT; | 119 | return -EFAULT; |
| 120 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | 120 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); |
| 121 | __get_user(mask, &act->sa_mask); | 121 | __get_user(mask, &act->sa_mask); |
| 122 | siginitset(&new_ka.sa.sa_mask, mask); | 122 | siginitset(&new_ka.sa.sa_mask, mask); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 125 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
| 126 | 126 | ||
| 127 | if (!ret && oact) { | 127 | if (!ret && oact) { |
| 128 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 128 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
| 129 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 129 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
| 130 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 130 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) |
| 131 | return -EFAULT; | 131 | return -EFAULT; |
| 132 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | 132 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
| 133 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | 133 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | return ret; | 136 | return ret; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | asmlinkage int | 139 | asmlinkage int |
| 140 | sys_sigaltstack(const stack_t *uss, stack_t *uoss) | 140 | sys_sigaltstack(const stack_t *uss, stack_t *uoss) |
| 141 | { | 141 | { |
| 142 | return do_sigaltstack(uss, uoss, rdusp()); | 142 | return do_sigaltstack(uss, uoss, rdusp()); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | 145 | ||
| 146 | /* | 146 | /* |
| 147 | * Do a signal return; undo the signal stack. | 147 | * Do a signal return; undo the signal stack. |
| 148 | * | 148 | * |
| 149 | * Keep the return code on the stack quadword aligned! | 149 | * Keep the return code on the stack quadword aligned! |
| 150 | * That makes the cache flush below easier. | 150 | * That makes the cache flush below easier. |
| 151 | */ | 151 | */ |
| 152 | 152 | ||
| 153 | struct sigframe | 153 | struct sigframe |
| 154 | { | 154 | { |
| 155 | long dummy_er0; | 155 | long dummy_er0; |
| 156 | long dummy_vector; | 156 | long dummy_vector; |
| 157 | #if defined(CONFIG_CPU_H8S) | 157 | #if defined(CONFIG_CPU_H8S) |
| 158 | short dummy_exr; | 158 | short dummy_exr; |
| 159 | #endif | 159 | #endif |
| 160 | long dummy_pc; | 160 | long dummy_pc; |
| 161 | char *pretcode; | 161 | char *pretcode; |
| 162 | unsigned char retcode[8]; | 162 | unsigned char retcode[8]; |
| 163 | unsigned long extramask[_NSIG_WORDS-1]; | 163 | unsigned long extramask[_NSIG_WORDS-1]; |
| 164 | struct sigcontext sc; | 164 | struct sigcontext sc; |
| 165 | int sig; | 165 | int sig; |
| 166 | } __attribute__((aligned(2),packed)); | 166 | } __attribute__((aligned(2),packed)); |
| 167 | 167 | ||
| 168 | struct rt_sigframe | 168 | struct rt_sigframe |
| 169 | { | 169 | { |
| 170 | long dummy_er0; | 170 | long dummy_er0; |
| 171 | long dummy_vector; | 171 | long dummy_vector; |
| 172 | #if defined(CONFIG_CPU_H8S) | 172 | #if defined(CONFIG_CPU_H8S) |
| 173 | short dummy_exr; | 173 | short dummy_exr; |
| 174 | #endif | 174 | #endif |
| 175 | long dummy_pc; | 175 | long dummy_pc; |
| 176 | char *pretcode; | 176 | char *pretcode; |
| 177 | struct siginfo *pinfo; | 177 | struct siginfo *pinfo; |
| 178 | void *puc; | 178 | void *puc; |
| 179 | unsigned char retcode[8]; | 179 | unsigned char retcode[8]; |
| 180 | struct siginfo info; | 180 | struct siginfo info; |
| 181 | struct ucontext uc; | 181 | struct ucontext uc; |
| 182 | int sig; | 182 | int sig; |
| 183 | } __attribute__((aligned(2),packed)); | 183 | } __attribute__((aligned(2),packed)); |
| 184 | 184 | ||
| 185 | static inline int | 185 | static inline int |
| 186 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, | 186 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, |
| 187 | int *pd0) | 187 | int *pd0) |
| 188 | { | 188 | { |
| 189 | int err = 0; | 189 | int err = 0; |
| 190 | unsigned int ccr; | 190 | unsigned int ccr; |
| 191 | unsigned int usp; | 191 | unsigned int usp; |
| 192 | unsigned int er0; | 192 | unsigned int er0; |
| 193 | 193 | ||
| 194 | /* Always make any pending restarted system calls return -EINTR */ | 194 | /* Always make any pending restarted system calls return -EINTR */ |
| 195 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 195 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
| 196 | 196 | ||
| 197 | #define COPY(r) err |= __get_user(regs->r, &usc->sc_##r) /* restore passed registers */ | 197 | #define COPY(r) err |= __get_user(regs->r, &usc->sc_##r) /* restore passed registers */ |
| 198 | COPY(er1); | 198 | COPY(er1); |
| 199 | COPY(er2); | 199 | COPY(er2); |
| 200 | COPY(er3); | 200 | COPY(er3); |
| 201 | COPY(er5); | 201 | COPY(er5); |
| 202 | COPY(pc); | 202 | COPY(pc); |
| 203 | ccr = regs->ccr & 0x10; | 203 | ccr = regs->ccr & 0x10; |
| 204 | COPY(ccr); | 204 | COPY(ccr); |
| 205 | #undef COPY | 205 | #undef COPY |
| 206 | regs->ccr &= 0xef; | 206 | regs->ccr &= 0xef; |
| 207 | regs->ccr |= ccr; | 207 | regs->ccr |= ccr; |
| 208 | regs->orig_er0 = -1; /* disable syscall checks */ | 208 | regs->orig_er0 = -1; /* disable syscall checks */ |
| 209 | err |= __get_user(usp, &usc->sc_usp); | 209 | err |= __get_user(usp, &usc->sc_usp); |
| 210 | wrusp(usp); | 210 | wrusp(usp); |
| 211 | 211 | ||
| 212 | err |= __get_user(er0, &usc->sc_er0); | 212 | err |= __get_user(er0, &usc->sc_er0); |
| 213 | *pd0 = er0; | 213 | *pd0 = er0; |
| 214 | return err; | 214 | return err; |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | asmlinkage int do_sigreturn(unsigned long __unused,...) | 217 | asmlinkage int do_sigreturn(unsigned long __unused,...) |
| 218 | { | 218 | { |
| 219 | struct pt_regs *regs = (struct pt_regs *) (&__unused - 1); | 219 | struct pt_regs *regs = (struct pt_regs *) (&__unused - 1); |
| 220 | unsigned long usp = rdusp(); | 220 | unsigned long usp = rdusp(); |
| 221 | struct sigframe *frame = (struct sigframe *)(usp - 4); | 221 | struct sigframe *frame = (struct sigframe *)(usp - 4); |
| 222 | sigset_t set; | 222 | sigset_t set; |
| 223 | int er0; | 223 | int er0; |
| 224 | 224 | ||
| 225 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 225 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 226 | goto badframe; | 226 | goto badframe; |
| 227 | if (__get_user(set.sig[0], &frame->sc.sc_mask) || | 227 | if (__get_user(set.sig[0], &frame->sc.sc_mask) || |
| 228 | (_NSIG_WORDS > 1 && | 228 | (_NSIG_WORDS > 1 && |
| 229 | __copy_from_user(&set.sig[1], &frame->extramask, | 229 | __copy_from_user(&set.sig[1], &frame->extramask, |
| 230 | sizeof(frame->extramask)))) | 230 | sizeof(frame->extramask)))) |
| 231 | goto badframe; | 231 | goto badframe; |
| 232 | 232 | ||
| 233 | sigdelsetmask(&set, ~_BLOCKABLE); | 233 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 234 | spin_lock_irq(¤t->sighand->siglock); | 234 | spin_lock_irq(¤t->sighand->siglock); |
| 235 | current->blocked = set; | 235 | current->blocked = set; |
| 236 | recalc_sigpending(); | 236 | recalc_sigpending(); |
| 237 | spin_unlock_irq(¤t->sighand->siglock); | 237 | spin_unlock_irq(¤t->sighand->siglock); |
| 238 | 238 | ||
| 239 | if (restore_sigcontext(regs, &frame->sc, &er0)) | 239 | if (restore_sigcontext(regs, &frame->sc, &er0)) |
| 240 | goto badframe; | 240 | goto badframe; |
| 241 | return er0; | 241 | return er0; |
| 242 | 242 | ||
| 243 | badframe: | 243 | badframe: |
| 244 | force_sig(SIGSEGV, current); | 244 | force_sig(SIGSEGV, current); |
| 245 | return 0; | 245 | return 0; |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | asmlinkage int do_rt_sigreturn(unsigned long __unused,...) | 248 | asmlinkage int do_rt_sigreturn(unsigned long __unused,...) |
| 249 | { | 249 | { |
| 250 | struct pt_regs *regs = (struct pt_regs *) &__unused; | 250 | struct pt_regs *regs = (struct pt_regs *) &__unused; |
| 251 | unsigned long usp = rdusp(); | 251 | unsigned long usp = rdusp(); |
| 252 | struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); | 252 | struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); |
| 253 | sigset_t set; | 253 | sigset_t set; |
| 254 | int er0; | 254 | int er0; |
| 255 | 255 | ||
| 256 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 256 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 257 | goto badframe; | 257 | goto badframe; |
| 258 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 258 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| 259 | goto badframe; | 259 | goto badframe; |
| 260 | 260 | ||
| 261 | sigdelsetmask(&set, ~_BLOCKABLE); | 261 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 262 | spin_unlock_irq(¤t->sighand->siglock); | 262 | spin_unlock_irq(¤t->sighand->siglock); |
| 263 | current->blocked = set; | 263 | current->blocked = set; |
| 264 | recalc_sigpending(); | 264 | recalc_sigpending(); |
| 265 | spin_lock_irq(¤t->sighand->siglock); | 265 | spin_lock_irq(¤t->sighand->siglock); |
| 266 | 266 | ||
| 267 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &er0)) | 267 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &er0)) |
| 268 | goto badframe; | 268 | goto badframe; |
| 269 | 269 | ||
| 270 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT) | 270 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT) |
| 271 | goto badframe; | 271 | goto badframe; |
| 272 | 272 | ||
| 273 | return er0; | 273 | return er0; |
| 274 | 274 | ||
| 275 | badframe: | 275 | badframe: |
| 276 | force_sig(SIGSEGV, current); | 276 | force_sig(SIGSEGV, current); |
| 277 | return 0; | 277 | return 0; |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | 280 | static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
| 281 | unsigned long mask) | 281 | unsigned long mask) |
| 282 | { | 282 | { |
| 283 | int err = 0; | 283 | int err = 0; |
| 284 | 284 | ||
| 285 | err |= __put_user(regs->er0, &sc->sc_er0); | 285 | err |= __put_user(regs->er0, &sc->sc_er0); |
| 286 | err |= __put_user(regs->er1, &sc->sc_er1); | 286 | err |= __put_user(regs->er1, &sc->sc_er1); |
| 287 | err |= __put_user(regs->er2, &sc->sc_er2); | 287 | err |= __put_user(regs->er2, &sc->sc_er2); |
| 288 | err |= __put_user(regs->er3, &sc->sc_er3); | 288 | err |= __put_user(regs->er3, &sc->sc_er3); |
| 289 | err |= __put_user(regs->er4, &sc->sc_er4); | 289 | err |= __put_user(regs->er4, &sc->sc_er4); |
| 290 | err |= __put_user(regs->er5, &sc->sc_er5); | 290 | err |= __put_user(regs->er5, &sc->sc_er5); |
| 291 | err |= __put_user(regs->er6, &sc->sc_er6); | 291 | err |= __put_user(regs->er6, &sc->sc_er6); |
| 292 | err |= __put_user(rdusp(), &sc->sc_usp); | 292 | err |= __put_user(rdusp(), &sc->sc_usp); |
| 293 | err |= __put_user(regs->pc, &sc->sc_pc); | 293 | err |= __put_user(regs->pc, &sc->sc_pc); |
| 294 | err |= __put_user(regs->ccr, &sc->sc_ccr); | 294 | err |= __put_user(regs->ccr, &sc->sc_ccr); |
| 295 | err |= __put_user(mask, &sc->sc_mask); | 295 | err |= __put_user(mask, &sc->sc_mask); |
| 296 | 296 | ||
| 297 | return err; | 297 | return err; |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | static inline void * | 300 | static inline void * |
| 301 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 301 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) |
| 302 | { | 302 | { |
| 303 | unsigned long usp; | 303 | unsigned long usp; |
| 304 | 304 | ||
| 305 | /* Default to using normal stack. */ | 305 | /* Default to using normal stack. */ |
| 306 | usp = rdusp(); | 306 | usp = rdusp(); |
| 307 | 307 | ||
| 308 | /* This is the X/Open sanctioned signal stack switching. */ | 308 | /* This is the X/Open sanctioned signal stack switching. */ |
| 309 | if (ka->sa.sa_flags & SA_ONSTACK) { | 309 | if (ka->sa.sa_flags & SA_ONSTACK) { |
| 310 | if (!on_sig_stack(usp)) | 310 | if (!sas_ss_flags(usp)) |
| 311 | usp = current->sas_ss_sp + current->sas_ss_size; | 311 | usp = current->sas_ss_sp + current->sas_ss_size; |
| 312 | } | 312 | } |
| 313 | return (void *)((usp - frame_size) & -8UL); | 313 | return (void *)((usp - frame_size) & -8UL); |
| 314 | } | 314 | } |
| 315 | 315 | ||
| 316 | static void setup_frame (int sig, struct k_sigaction *ka, | 316 | static void setup_frame (int sig, struct k_sigaction *ka, |
| 317 | sigset_t *set, struct pt_regs *regs) | 317 | sigset_t *set, struct pt_regs *regs) |
| 318 | { | 318 | { |
| 319 | struct sigframe *frame; | 319 | struct sigframe *frame; |
| 320 | int err = 0; | 320 | int err = 0; |
| 321 | int usig; | 321 | int usig; |
| 322 | unsigned char *ret; | 322 | unsigned char *ret; |
| 323 | 323 | ||
| 324 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 324 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
| 325 | 325 | ||
| 326 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 326 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 327 | goto give_sigsegv; | 327 | goto give_sigsegv; |
| 328 | 328 | ||
| 329 | usig = current_thread_info()->exec_domain | 329 | usig = current_thread_info()->exec_domain |
| 330 | && current_thread_info()->exec_domain->signal_invmap | 330 | && current_thread_info()->exec_domain->signal_invmap |
| 331 | && sig < 32 | 331 | && sig < 32 |
| 332 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 332 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 333 | : sig; | 333 | : sig; |
| 334 | 334 | ||
| 335 | err |= __put_user(usig, &frame->sig); | 335 | err |= __put_user(usig, &frame->sig); |
| 336 | if (err) | 336 | if (err) |
| 337 | goto give_sigsegv; | 337 | goto give_sigsegv; |
| 338 | 338 | ||
| 339 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); | 339 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); |
| 340 | if (err) | 340 | if (err) |
| 341 | goto give_sigsegv; | 341 | goto give_sigsegv; |
| 342 | 342 | ||
| 343 | if (_NSIG_WORDS > 1) { | 343 | if (_NSIG_WORDS > 1) { |
| 344 | err |= copy_to_user(frame->extramask, &set->sig[1], | 344 | err |= copy_to_user(frame->extramask, &set->sig[1], |
| 345 | sizeof(frame->extramask)); | 345 | sizeof(frame->extramask)); |
| 346 | if (err) | 346 | if (err) |
| 347 | goto give_sigsegv; | 347 | goto give_sigsegv; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | ret = frame->retcode; | 350 | ret = frame->retcode; |
| 351 | if (ka->sa.sa_flags & SA_RESTORER) | 351 | if (ka->sa.sa_flags & SA_RESTORER) |
| 352 | ret = (unsigned char *)(ka->sa.sa_restorer); | 352 | ret = (unsigned char *)(ka->sa.sa_restorer); |
| 353 | else { | 353 | else { |
| 354 | /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */ | 354 | /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */ |
| 355 | err != __put_user(0x1a80f800 + (__NR_sigreturn & 0xff), | 355 | err != __put_user(0x1a80f800 + (__NR_sigreturn & 0xff), |
| 356 | (unsigned long *)(frame->retcode + 0)); | 356 | (unsigned long *)(frame->retcode + 0)); |
| 357 | err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4)); | 357 | err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4)); |
| 358 | } | 358 | } |
| 359 | 359 | ||
| 360 | /* Set up to return from userspace. */ | 360 | /* Set up to return from userspace. */ |
| 361 | err |= __put_user(ret, &frame->pretcode); | 361 | err |= __put_user(ret, &frame->pretcode); |
| 362 | 362 | ||
| 363 | if (err) | 363 | if (err) |
| 364 | goto give_sigsegv; | 364 | goto give_sigsegv; |
| 365 | 365 | ||
| 366 | /* Set up registers for signal handler */ | 366 | /* Set up registers for signal handler */ |
| 367 | wrusp ((unsigned long) frame); | 367 | wrusp ((unsigned long) frame); |
| 368 | regs->pc = (unsigned long) ka->sa.sa_handler; | 368 | regs->pc = (unsigned long) ka->sa.sa_handler; |
| 369 | regs->er0 = (current_thread_info()->exec_domain | 369 | regs->er0 = (current_thread_info()->exec_domain |
| 370 | && current_thread_info()->exec_domain->signal_invmap | 370 | && current_thread_info()->exec_domain->signal_invmap |
| 371 | && sig < 32 | 371 | && sig < 32 |
| 372 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 372 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 373 | : sig); | 373 | : sig); |
| 374 | regs->er1 = (unsigned long)&(frame->sc); | 374 | regs->er1 = (unsigned long)&(frame->sc); |
| 375 | regs->er5 = current->mm->start_data; /* GOT base */ | 375 | regs->er5 = current->mm->start_data; /* GOT base */ |
| 376 | 376 | ||
| 377 | return; | 377 | return; |
| 378 | 378 | ||
| 379 | give_sigsegv: | 379 | give_sigsegv: |
| 380 | force_sigsegv(sig, current); | 380 | force_sigsegv(sig, current); |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | 383 | static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, |
| 384 | sigset_t *set, struct pt_regs *regs) | 384 | sigset_t *set, struct pt_regs *regs) |
| 385 | { | 385 | { |
| 386 | struct rt_sigframe *frame; | 386 | struct rt_sigframe *frame; |
| 387 | int err = 0; | 387 | int err = 0; |
| 388 | int usig; | 388 | int usig; |
| 389 | unsigned char *ret; | 389 | unsigned char *ret; |
| 390 | 390 | ||
| 391 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 391 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
| 392 | 392 | ||
| 393 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 393 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 394 | goto give_sigsegv; | 394 | goto give_sigsegv; |
| 395 | 395 | ||
| 396 | usig = current_thread_info()->exec_domain | 396 | usig = current_thread_info()->exec_domain |
| 397 | && current_thread_info()->exec_domain->signal_invmap | 397 | && current_thread_info()->exec_domain->signal_invmap |
| 398 | && sig < 32 | 398 | && sig < 32 |
| 399 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 399 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 400 | : sig; | 400 | : sig; |
| 401 | 401 | ||
| 402 | err |= __put_user(usig, &frame->sig); | 402 | err |= __put_user(usig, &frame->sig); |
| 403 | if (err) | 403 | if (err) |
| 404 | goto give_sigsegv; | 404 | goto give_sigsegv; |
| 405 | 405 | ||
| 406 | err |= __put_user(&frame->info, &frame->pinfo); | 406 | err |= __put_user(&frame->info, &frame->pinfo); |
| 407 | err |= __put_user(&frame->uc, &frame->puc); | 407 | err |= __put_user(&frame->uc, &frame->puc); |
| 408 | err |= copy_siginfo_to_user(&frame->info, info); | 408 | err |= copy_siginfo_to_user(&frame->info, info); |
| 409 | if (err) | 409 | if (err) |
| 410 | goto give_sigsegv; | 410 | goto give_sigsegv; |
| 411 | 411 | ||
| 412 | /* Create the ucontext. */ | 412 | /* Create the ucontext. */ |
| 413 | err |= __put_user(0, &frame->uc.uc_flags); | 413 | err |= __put_user(0, &frame->uc.uc_flags); |
| 414 | err |= __put_user(0, &frame->uc.uc_link); | 414 | err |= __put_user(0, &frame->uc.uc_link); |
| 415 | err |= __put_user((void *)current->sas_ss_sp, | 415 | err |= __put_user((void *)current->sas_ss_sp, |
| 416 | &frame->uc.uc_stack.ss_sp); | 416 | &frame->uc.uc_stack.ss_sp); |
| 417 | err |= __put_user(sas_ss_flags(rdusp()), | 417 | err |= __put_user(sas_ss_flags(rdusp()), |
| 418 | &frame->uc.uc_stack.ss_flags); | 418 | &frame->uc.uc_stack.ss_flags); |
| 419 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 419 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
| 420 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); | 420 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); |
| 421 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); | 421 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 422 | if (err) | 422 | if (err) |
| 423 | goto give_sigsegv; | 423 | goto give_sigsegv; |
| 424 | 424 | ||
| 425 | /* Set up to return from userspace. */ | 425 | /* Set up to return from userspace. */ |
| 426 | ret = frame->retcode; | 426 | ret = frame->retcode; |
| 427 | if (ka->sa.sa_flags & SA_RESTORER) | 427 | if (ka->sa.sa_flags & SA_RESTORER) |
| 428 | ret = (unsigned char *)(ka->sa.sa_restorer); | 428 | ret = (unsigned char *)(ka->sa.sa_restorer); |
| 429 | else { | 429 | else { |
| 430 | /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */ | 430 | /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */ |
| 431 | err != __put_user(0x1a80f800 + (__NR_sigreturn & 0xff), | 431 | err != __put_user(0x1a80f800 + (__NR_sigreturn & 0xff), |
| 432 | (unsigned long *)(frame->retcode + 0)); | 432 | (unsigned long *)(frame->retcode + 0)); |
| 433 | err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4)); | 433 | err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4)); |
| 434 | } | 434 | } |
| 435 | err |= __put_user(ret, &frame->pretcode); | 435 | err |= __put_user(ret, &frame->pretcode); |
| 436 | 436 | ||
| 437 | if (err) | 437 | if (err) |
| 438 | goto give_sigsegv; | 438 | goto give_sigsegv; |
| 439 | 439 | ||
| 440 | /* Set up registers for signal handler */ | 440 | /* Set up registers for signal handler */ |
| 441 | wrusp ((unsigned long) frame); | 441 | wrusp ((unsigned long) frame); |
| 442 | regs->pc = (unsigned long) ka->sa.sa_handler; | 442 | regs->pc = (unsigned long) ka->sa.sa_handler; |
| 443 | regs->er0 = (current_thread_info()->exec_domain | 443 | regs->er0 = (current_thread_info()->exec_domain |
| 444 | && current_thread_info()->exec_domain->signal_invmap | 444 | && current_thread_info()->exec_domain->signal_invmap |
| 445 | && sig < 32 | 445 | && sig < 32 |
| 446 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 446 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 447 | : sig); | 447 | : sig); |
| 448 | regs->er1 = (unsigned long)&(frame->info); | 448 | regs->er1 = (unsigned long)&(frame->info); |
| 449 | regs->er2 = (unsigned long)&frame->uc; | 449 | regs->er2 = (unsigned long)&frame->uc; |
| 450 | regs->er5 = current->mm->start_data; /* GOT base */ | 450 | regs->er5 = current->mm->start_data; /* GOT base */ |
| 451 | 451 | ||
| 452 | return; | 452 | return; |
| 453 | 453 | ||
| 454 | give_sigsegv: | 454 | give_sigsegv: |
| 455 | force_sigsegv(sig, current); | 455 | force_sigsegv(sig, current); |
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | /* | 458 | /* |
| 459 | * OK, we're invoking a handler | 459 | * OK, we're invoking a handler |
| 460 | */ | 460 | */ |
| 461 | static void | 461 | static void |
| 462 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 462 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
| 463 | sigset_t *oldset, struct pt_regs * regs) | 463 | sigset_t *oldset, struct pt_regs * regs) |
| 464 | { | 464 | { |
| 465 | /* are we from a system call? */ | 465 | /* are we from a system call? */ |
| 466 | if (regs->orig_er0 >= 0) { | 466 | if (regs->orig_er0 >= 0) { |
| 467 | switch (regs->er0) { | 467 | switch (regs->er0) { |
| 468 | case -ERESTART_RESTARTBLOCK: | 468 | case -ERESTART_RESTARTBLOCK: |
| 469 | case -ERESTARTNOHAND: | 469 | case -ERESTARTNOHAND: |
| 470 | regs->er0 = -EINTR; | 470 | regs->er0 = -EINTR; |
| 471 | break; | 471 | break; |
| 472 | 472 | ||
| 473 | case -ERESTARTSYS: | 473 | case -ERESTARTSYS: |
| 474 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 474 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
| 475 | regs->er0 = -EINTR; | 475 | regs->er0 = -EINTR; |
| 476 | break; | 476 | break; |
| 477 | } | 477 | } |
| 478 | /* fallthrough */ | 478 | /* fallthrough */ |
| 479 | case -ERESTARTNOINTR: | 479 | case -ERESTARTNOINTR: |
| 480 | regs->er0 = regs->orig_er0; | 480 | regs->er0 = regs->orig_er0; |
| 481 | regs->pc -= 2; | 481 | regs->pc -= 2; |
| 482 | } | 482 | } |
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | /* set up the stack frame */ | 485 | /* set up the stack frame */ |
| 486 | if (ka->sa.sa_flags & SA_SIGINFO) | 486 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 487 | setup_rt_frame(sig, ka, info, oldset, regs); | 487 | setup_rt_frame(sig, ka, info, oldset, regs); |
| 488 | else | 488 | else |
| 489 | setup_frame(sig, ka, oldset, regs); | 489 | setup_frame(sig, ka, oldset, regs); |
| 490 | 490 | ||
| 491 | spin_lock_irq(¤t->sighand->siglock); | 491 | spin_lock_irq(¤t->sighand->siglock); |
| 492 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 492 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
| 493 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 493 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 494 | sigaddset(¤t->blocked,sig); | 494 | sigaddset(¤t->blocked,sig); |
| 495 | recalc_sigpending(); | 495 | recalc_sigpending(); |
| 496 | spin_unlock_irq(¤t->sighand->siglock); | 496 | spin_unlock_irq(¤t->sighand->siglock); |
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | /* | 499 | /* |
| 500 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 500 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 501 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 501 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 502 | * mistake. | 502 | * mistake. |
| 503 | */ | 503 | */ |
| 504 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset) | 504 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset) |
| 505 | { | 505 | { |
| 506 | siginfo_t info; | 506 | siginfo_t info; |
| 507 | int signr; | 507 | int signr; |
| 508 | struct k_sigaction ka; | 508 | struct k_sigaction ka; |
| 509 | 509 | ||
| 510 | /* | 510 | /* |
| 511 | * We want the common case to go fast, which | 511 | * We want the common case to go fast, which |
| 512 | * is why we may in certain cases get here from | 512 | * is why we may in certain cases get here from |
| 513 | * kernel mode. Just return without doing anything | 513 | * kernel mode. Just return without doing anything |
| 514 | * if so. | 514 | * if so. |
| 515 | */ | 515 | */ |
| 516 | if ((regs->ccr & 0x10)) | 516 | if ((regs->ccr & 0x10)) |
| 517 | return 1; | 517 | return 1; |
| 518 | 518 | ||
| 519 | if (try_to_freeze()) | 519 | if (try_to_freeze()) |
| 520 | goto no_signal; | 520 | goto no_signal; |
| 521 | 521 | ||
| 522 | current->thread.esp0 = (unsigned long) regs; | 522 | current->thread.esp0 = (unsigned long) regs; |
| 523 | 523 | ||
| 524 | if (!oldset) | 524 | if (!oldset) |
| 525 | oldset = ¤t->blocked; | 525 | oldset = ¤t->blocked; |
| 526 | 526 | ||
| 527 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 527 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 528 | if (signr > 0) { | 528 | if (signr > 0) { |
| 529 | /* Whee! Actually deliver the signal. */ | 529 | /* Whee! Actually deliver the signal. */ |
| 530 | handle_signal(signr, &info, &ka, oldset, regs); | 530 | handle_signal(signr, &info, &ka, oldset, regs); |
| 531 | return 1; | 531 | return 1; |
| 532 | } | 532 | } |
| 533 | no_signal: | 533 | no_signal: |
| 534 | /* Did we come from a system call? */ | 534 | /* Did we come from a system call? */ |
| 535 | if (regs->orig_er0 >= 0) { | 535 | if (regs->orig_er0 >= 0) { |
| 536 | /* Restart the system call - no handlers present */ | 536 | /* Restart the system call - no handlers present */ |
| 537 | if (regs->er0 == -ERESTARTNOHAND || | 537 | if (regs->er0 == -ERESTARTNOHAND || |
| 538 | regs->er0 == -ERESTARTSYS || | 538 | regs->er0 == -ERESTARTSYS || |
| 539 | regs->er0 == -ERESTARTNOINTR) { | 539 | regs->er0 == -ERESTARTNOINTR) { |
| 540 | regs->er0 = regs->orig_er0; | 540 | regs->er0 = regs->orig_er0; |
| 541 | regs->pc -= 2; | 541 | regs->pc -= 2; |
| 542 | } | 542 | } |
| 543 | if (regs->er0 == -ERESTART_RESTARTBLOCK){ | 543 | if (regs->er0 == -ERESTART_RESTARTBLOCK){ |
| 544 | regs->er0 = __NR_restart_syscall; | 544 | regs->er0 = __NR_restart_syscall; |
| 545 | regs->pc -= 2; | 545 | regs->pc -= 2; |
| 546 | } | 546 | } |
| 547 | } | 547 | } |
| 548 | return 0; | 548 | return 0; |
| 549 | } | 549 | } |
| 550 | 550 |
arch/m68k/kernel/signal.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/m68k/kernel/signal.c | 2 | * linux/arch/m68k/kernel/signal.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1991, 1992 Linus Torvalds | 4 | * Copyright (C) 1991, 1992 Linus Torvalds |
| 5 | * | 5 | * |
| 6 | * This file is subject to the terms and conditions of the GNU General Public | 6 | * This file is subject to the terms and conditions of the GNU General Public |
| 7 | * License. See the file COPYING in the main directory of this archive | 7 | * License. See the file COPYING in the main directory of this archive |
| 8 | * for more details. | 8 | * for more details. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | /* | 11 | /* |
| 12 | * Linux/m68k support by Hamish Macdonald | 12 | * Linux/m68k support by Hamish Macdonald |
| 13 | * | 13 | * |
| 14 | * 68060 fixes by Jesper Skov | 14 | * 68060 fixes by Jesper Skov |
| 15 | * | 15 | * |
| 16 | * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab | 16 | * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab |
| 17 | * | 17 | * |
| 18 | * mathemu support by Roman Zippel | 18 | * mathemu support by Roman Zippel |
| 19 | * (Note: fpstate in the signal context is completely ignored for the emulator | 19 | * (Note: fpstate in the signal context is completely ignored for the emulator |
| 20 | * and the internal floating point format is put on stack) | 20 | * and the internal floating point format is put on stack) |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | /* | 23 | /* |
| 24 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on | 24 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on |
| 25 | * Atari :-) Current limitation: Only one sigstack can be active at one time. | 25 | * Atari :-) Current limitation: Only one sigstack can be active at one time. |
| 26 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, | 26 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, |
| 27 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested | 27 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested |
| 28 | * signal handlers! | 28 | * signal handlers! |
| 29 | */ | 29 | */ |
| 30 | 30 | ||
| 31 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
| 32 | #include <linux/mm.h> | 32 | #include <linux/mm.h> |
| 33 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
| 34 | #include <linux/signal.h> | 34 | #include <linux/signal.h> |
| 35 | #include <linux/syscalls.h> | 35 | #include <linux/syscalls.h> |
| 36 | #include <linux/errno.h> | 36 | #include <linux/errno.h> |
| 37 | #include <linux/wait.h> | 37 | #include <linux/wait.h> |
| 38 | #include <linux/ptrace.h> | 38 | #include <linux/ptrace.h> |
| 39 | #include <linux/unistd.h> | 39 | #include <linux/unistd.h> |
| 40 | #include <linux/stddef.h> | 40 | #include <linux/stddef.h> |
| 41 | #include <linux/highuid.h> | 41 | #include <linux/highuid.h> |
| 42 | #include <linux/personality.h> | 42 | #include <linux/personality.h> |
| 43 | #include <linux/tty.h> | 43 | #include <linux/tty.h> |
| 44 | #include <linux/binfmts.h> | 44 | #include <linux/binfmts.h> |
| 45 | 45 | ||
| 46 | #include <asm/setup.h> | 46 | #include <asm/setup.h> |
| 47 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
| 48 | #include <asm/pgtable.h> | 48 | #include <asm/pgtable.h> |
| 49 | #include <asm/traps.h> | 49 | #include <asm/traps.h> |
| 50 | #include <asm/ucontext.h> | 50 | #include <asm/ucontext.h> |
| 51 | 51 | ||
| 52 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 52 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 53 | 53 | ||
| 54 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); | 54 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); |
| 55 | 55 | ||
| 56 | const int frame_extra_sizes[16] = { | 56 | const int frame_extra_sizes[16] = { |
| 57 | [1] = -1, /* sizeof(((struct frame *)0)->un.fmt1), */ | 57 | [1] = -1, /* sizeof(((struct frame *)0)->un.fmt1), */ |
| 58 | [2] = sizeof(((struct frame *)0)->un.fmt2), | 58 | [2] = sizeof(((struct frame *)0)->un.fmt2), |
| 59 | [3] = sizeof(((struct frame *)0)->un.fmt3), | 59 | [3] = sizeof(((struct frame *)0)->un.fmt3), |
| 60 | [4] = sizeof(((struct frame *)0)->un.fmt4), | 60 | [4] = sizeof(((struct frame *)0)->un.fmt4), |
| 61 | [5] = -1, /* sizeof(((struct frame *)0)->un.fmt5), */ | 61 | [5] = -1, /* sizeof(((struct frame *)0)->un.fmt5), */ |
| 62 | [6] = -1, /* sizeof(((struct frame *)0)->un.fmt6), */ | 62 | [6] = -1, /* sizeof(((struct frame *)0)->un.fmt6), */ |
| 63 | [7] = sizeof(((struct frame *)0)->un.fmt7), | 63 | [7] = sizeof(((struct frame *)0)->un.fmt7), |
| 64 | [8] = -1, /* sizeof(((struct frame *)0)->un.fmt8), */ | 64 | [8] = -1, /* sizeof(((struct frame *)0)->un.fmt8), */ |
| 65 | [9] = sizeof(((struct frame *)0)->un.fmt9), | 65 | [9] = sizeof(((struct frame *)0)->un.fmt9), |
| 66 | [10] = sizeof(((struct frame *)0)->un.fmta), | 66 | [10] = sizeof(((struct frame *)0)->un.fmta), |
| 67 | [11] = sizeof(((struct frame *)0)->un.fmtb), | 67 | [11] = sizeof(((struct frame *)0)->un.fmtb), |
| 68 | [12] = -1, /* sizeof(((struct frame *)0)->un.fmtc), */ | 68 | [12] = -1, /* sizeof(((struct frame *)0)->un.fmtc), */ |
| 69 | [13] = -1, /* sizeof(((struct frame *)0)->un.fmtd), */ | 69 | [13] = -1, /* sizeof(((struct frame *)0)->un.fmtd), */ |
| 70 | [14] = -1, /* sizeof(((struct frame *)0)->un.fmte), */ | 70 | [14] = -1, /* sizeof(((struct frame *)0)->un.fmte), */ |
| 71 | [15] = -1, /* sizeof(((struct frame *)0)->un.fmtf), */ | 71 | [15] = -1, /* sizeof(((struct frame *)0)->un.fmtf), */ |
| 72 | }; | 72 | }; |
| 73 | 73 | ||
| 74 | /* | 74 | /* |
| 75 | * Atomically swap in the new signal mask, and wait for a signal. | 75 | * Atomically swap in the new signal mask, and wait for a signal. |
| 76 | */ | 76 | */ |
| 77 | asmlinkage int do_sigsuspend(struct pt_regs *regs) | 77 | asmlinkage int do_sigsuspend(struct pt_regs *regs) |
| 78 | { | 78 | { |
| 79 | old_sigset_t mask = regs->d3; | 79 | old_sigset_t mask = regs->d3; |
| 80 | sigset_t saveset; | 80 | sigset_t saveset; |
| 81 | 81 | ||
| 82 | mask &= _BLOCKABLE; | 82 | mask &= _BLOCKABLE; |
| 83 | saveset = current->blocked; | 83 | saveset = current->blocked; |
| 84 | siginitset(¤t->blocked, mask); | 84 | siginitset(¤t->blocked, mask); |
| 85 | recalc_sigpending(); | 85 | recalc_sigpending(); |
| 86 | 86 | ||
| 87 | regs->d0 = -EINTR; | 87 | regs->d0 = -EINTR; |
| 88 | while (1) { | 88 | while (1) { |
| 89 | current->state = TASK_INTERRUPTIBLE; | 89 | current->state = TASK_INTERRUPTIBLE; |
| 90 | schedule(); | 90 | schedule(); |
| 91 | if (do_signal(&saveset, regs)) | 91 | if (do_signal(&saveset, regs)) |
| 92 | return -EINTR; | 92 | return -EINTR; |
| 93 | } | 93 | } |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | asmlinkage int | 96 | asmlinkage int |
| 97 | do_rt_sigsuspend(struct pt_regs *regs) | 97 | do_rt_sigsuspend(struct pt_regs *regs) |
| 98 | { | 98 | { |
| 99 | sigset_t __user *unewset = (sigset_t __user *)regs->d1; | 99 | sigset_t __user *unewset = (sigset_t __user *)regs->d1; |
| 100 | size_t sigsetsize = (size_t)regs->d2; | 100 | size_t sigsetsize = (size_t)regs->d2; |
| 101 | sigset_t saveset, newset; | 101 | sigset_t saveset, newset; |
| 102 | 102 | ||
| 103 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 103 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
| 104 | if (sigsetsize != sizeof(sigset_t)) | 104 | if (sigsetsize != sizeof(sigset_t)) |
| 105 | return -EINVAL; | 105 | return -EINVAL; |
| 106 | 106 | ||
| 107 | if (copy_from_user(&newset, unewset, sizeof(newset))) | 107 | if (copy_from_user(&newset, unewset, sizeof(newset))) |
| 108 | return -EFAULT; | 108 | return -EFAULT; |
| 109 | sigdelsetmask(&newset, ~_BLOCKABLE); | 109 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 110 | 110 | ||
| 111 | saveset = current->blocked; | 111 | saveset = current->blocked; |
| 112 | current->blocked = newset; | 112 | current->blocked = newset; |
| 113 | recalc_sigpending(); | 113 | recalc_sigpending(); |
| 114 | 114 | ||
| 115 | regs->d0 = -EINTR; | 115 | regs->d0 = -EINTR; |
| 116 | while (1) { | 116 | while (1) { |
| 117 | current->state = TASK_INTERRUPTIBLE; | 117 | current->state = TASK_INTERRUPTIBLE; |
| 118 | schedule(); | 118 | schedule(); |
| 119 | if (do_signal(&saveset, regs)) | 119 | if (do_signal(&saveset, regs)) |
| 120 | return -EINTR; | 120 | return -EINTR; |
| 121 | } | 121 | } |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | asmlinkage int | 124 | asmlinkage int |
| 125 | sys_sigaction(int sig, const struct old_sigaction __user *act, | 125 | sys_sigaction(int sig, const struct old_sigaction __user *act, |
| 126 | struct old_sigaction __user *oact) | 126 | struct old_sigaction __user *oact) |
| 127 | { | 127 | { |
| 128 | struct k_sigaction new_ka, old_ka; | 128 | struct k_sigaction new_ka, old_ka; |
| 129 | int ret; | 129 | int ret; |
| 130 | 130 | ||
| 131 | if (act) { | 131 | if (act) { |
| 132 | old_sigset_t mask; | 132 | old_sigset_t mask; |
| 133 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 133 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
| 134 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 134 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
| 135 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 135 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) |
| 136 | return -EFAULT; | 136 | return -EFAULT; |
| 137 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | 137 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); |
| 138 | __get_user(mask, &act->sa_mask); | 138 | __get_user(mask, &act->sa_mask); |
| 139 | siginitset(&new_ka.sa.sa_mask, mask); | 139 | siginitset(&new_ka.sa.sa_mask, mask); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 142 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
| 143 | 143 | ||
| 144 | if (!ret && oact) { | 144 | if (!ret && oact) { |
| 145 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 145 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
| 146 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 146 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
| 147 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 147 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) |
| 148 | return -EFAULT; | 148 | return -EFAULT; |
| 149 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | 149 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
| 150 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | 150 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | return ret; | 153 | return ret; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | asmlinkage int | 156 | asmlinkage int |
| 157 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) | 157 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) |
| 158 | { | 158 | { |
| 159 | return do_sigaltstack(uss, uoss, rdusp()); | 159 | return do_sigaltstack(uss, uoss, rdusp()); |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | 162 | ||
| 163 | /* | 163 | /* |
| 164 | * Do a signal return; undo the signal stack. | 164 | * Do a signal return; undo the signal stack. |
| 165 | * | 165 | * |
| 166 | * Keep the return code on the stack quadword aligned! | 166 | * Keep the return code on the stack quadword aligned! |
| 167 | * That makes the cache flush below easier. | 167 | * That makes the cache flush below easier. |
| 168 | */ | 168 | */ |
| 169 | 169 | ||
| 170 | struct sigframe | 170 | struct sigframe |
| 171 | { | 171 | { |
| 172 | char __user *pretcode; | 172 | char __user *pretcode; |
| 173 | int sig; | 173 | int sig; |
| 174 | int code; | 174 | int code; |
| 175 | struct sigcontext __user *psc; | 175 | struct sigcontext __user *psc; |
| 176 | char retcode[8]; | 176 | char retcode[8]; |
| 177 | unsigned long extramask[_NSIG_WORDS-1]; | 177 | unsigned long extramask[_NSIG_WORDS-1]; |
| 178 | struct sigcontext sc; | 178 | struct sigcontext sc; |
| 179 | }; | 179 | }; |
| 180 | 180 | ||
| 181 | struct rt_sigframe | 181 | struct rt_sigframe |
| 182 | { | 182 | { |
| 183 | char __user *pretcode; | 183 | char __user *pretcode; |
| 184 | int sig; | 184 | int sig; |
| 185 | struct siginfo __user *pinfo; | 185 | struct siginfo __user *pinfo; |
| 186 | void __user *puc; | 186 | void __user *puc; |
| 187 | char retcode[8]; | 187 | char retcode[8]; |
| 188 | struct siginfo info; | 188 | struct siginfo info; |
| 189 | struct ucontext uc; | 189 | struct ucontext uc; |
| 190 | }; | 190 | }; |
| 191 | 191 | ||
| 192 | 192 | ||
| 193 | static unsigned char fpu_version; /* version number of fpu, set by setup_frame */ | 193 | static unsigned char fpu_version; /* version number of fpu, set by setup_frame */ |
| 194 | 194 | ||
| 195 | static inline int restore_fpu_state(struct sigcontext *sc) | 195 | static inline int restore_fpu_state(struct sigcontext *sc) |
| 196 | { | 196 | { |
| 197 | int err = 1; | 197 | int err = 1; |
| 198 | 198 | ||
| 199 | if (FPU_IS_EMU) { | 199 | if (FPU_IS_EMU) { |
| 200 | /* restore registers */ | 200 | /* restore registers */ |
| 201 | memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); | 201 | memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); |
| 202 | memcpy(current->thread.fp, sc->sc_fpregs, 24); | 202 | memcpy(current->thread.fp, sc->sc_fpregs, 24); |
| 203 | return 0; | 203 | return 0; |
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { | 206 | if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { |
| 207 | /* Verify the frame format. */ | 207 | /* Verify the frame format. */ |
| 208 | if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) | 208 | if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) |
| 209 | goto out; | 209 | goto out; |
| 210 | if (CPU_IS_020_OR_030) { | 210 | if (CPU_IS_020_OR_030) { |
| 211 | if (m68k_fputype & FPU_68881 && | 211 | if (m68k_fputype & FPU_68881 && |
| 212 | !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4)) | 212 | !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4)) |
| 213 | goto out; | 213 | goto out; |
| 214 | if (m68k_fputype & FPU_68882 && | 214 | if (m68k_fputype & FPU_68882 && |
| 215 | !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4)) | 215 | !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4)) |
| 216 | goto out; | 216 | goto out; |
| 217 | } else if (CPU_IS_040) { | 217 | } else if (CPU_IS_040) { |
| 218 | if (!(sc->sc_fpstate[1] == 0x00 || | 218 | if (!(sc->sc_fpstate[1] == 0x00 || |
| 219 | sc->sc_fpstate[1] == 0x28 || | 219 | sc->sc_fpstate[1] == 0x28 || |
| 220 | sc->sc_fpstate[1] == 0x60)) | 220 | sc->sc_fpstate[1] == 0x60)) |
| 221 | goto out; | 221 | goto out; |
| 222 | } else if (CPU_IS_060) { | 222 | } else if (CPU_IS_060) { |
| 223 | if (!(sc->sc_fpstate[3] == 0x00 || | 223 | if (!(sc->sc_fpstate[3] == 0x00 || |
| 224 | sc->sc_fpstate[3] == 0x60 || | 224 | sc->sc_fpstate[3] == 0x60 || |
| 225 | sc->sc_fpstate[3] == 0xe0)) | 225 | sc->sc_fpstate[3] == 0xe0)) |
| 226 | goto out; | 226 | goto out; |
| 227 | } else | 227 | } else |
| 228 | goto out; | 228 | goto out; |
| 229 | 229 | ||
| 230 | __asm__ volatile (".chip 68k/68881\n\t" | 230 | __asm__ volatile (".chip 68k/68881\n\t" |
| 231 | "fmovemx %0,%%fp0-%%fp1\n\t" | 231 | "fmovemx %0,%%fp0-%%fp1\n\t" |
| 232 | "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" | 232 | "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" |
| 233 | ".chip 68k" | 233 | ".chip 68k" |
| 234 | : /* no outputs */ | 234 | : /* no outputs */ |
| 235 | : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); | 235 | : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); |
| 236 | } | 236 | } |
| 237 | __asm__ volatile (".chip 68k/68881\n\t" | 237 | __asm__ volatile (".chip 68k/68881\n\t" |
| 238 | "frestore %0\n\t" | 238 | "frestore %0\n\t" |
| 239 | ".chip 68k" : : "m" (*sc->sc_fpstate)); | 239 | ".chip 68k" : : "m" (*sc->sc_fpstate)); |
| 240 | err = 0; | 240 | err = 0; |
| 241 | 241 | ||
| 242 | out: | 242 | out: |
| 243 | return err; | 243 | return err; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | #define FPCONTEXT_SIZE 216 | 246 | #define FPCONTEXT_SIZE 216 |
| 247 | #define uc_fpstate uc_filler[0] | 247 | #define uc_fpstate uc_filler[0] |
| 248 | #define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] | 248 | #define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] |
| 249 | #define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] | 249 | #define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] |
| 250 | 250 | ||
| 251 | static inline int rt_restore_fpu_state(struct ucontext __user *uc) | 251 | static inline int rt_restore_fpu_state(struct ucontext __user *uc) |
| 252 | { | 252 | { |
| 253 | unsigned char fpstate[FPCONTEXT_SIZE]; | 253 | unsigned char fpstate[FPCONTEXT_SIZE]; |
| 254 | int context_size = CPU_IS_060 ? 8 : 0; | 254 | int context_size = CPU_IS_060 ? 8 : 0; |
| 255 | fpregset_t fpregs; | 255 | fpregset_t fpregs; |
| 256 | int err = 1; | 256 | int err = 1; |
| 257 | 257 | ||
| 258 | if (FPU_IS_EMU) { | 258 | if (FPU_IS_EMU) { |
| 259 | /* restore fpu control register */ | 259 | /* restore fpu control register */ |
| 260 | if (__copy_from_user(current->thread.fpcntl, | 260 | if (__copy_from_user(current->thread.fpcntl, |
| 261 | uc->uc_mcontext.fpregs.f_fpcntl, 12)) | 261 | uc->uc_mcontext.fpregs.f_fpcntl, 12)) |
| 262 | goto out; | 262 | goto out; |
| 263 | /* restore all other fpu register */ | 263 | /* restore all other fpu register */ |
| 264 | if (__copy_from_user(current->thread.fp, | 264 | if (__copy_from_user(current->thread.fp, |
| 265 | uc->uc_mcontext.fpregs.f_fpregs, 96)) | 265 | uc->uc_mcontext.fpregs.f_fpregs, 96)) |
| 266 | goto out; | 266 | goto out; |
| 267 | return 0; | 267 | return 0; |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate)) | 270 | if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate)) |
| 271 | goto out; | 271 | goto out; |
| 272 | if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { | 272 | if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { |
| 273 | if (!CPU_IS_060) | 273 | if (!CPU_IS_060) |
| 274 | context_size = fpstate[1]; | 274 | context_size = fpstate[1]; |
| 275 | /* Verify the frame format. */ | 275 | /* Verify the frame format. */ |
| 276 | if (!CPU_IS_060 && (fpstate[0] != fpu_version)) | 276 | if (!CPU_IS_060 && (fpstate[0] != fpu_version)) |
| 277 | goto out; | 277 | goto out; |
| 278 | if (CPU_IS_020_OR_030) { | 278 | if (CPU_IS_020_OR_030) { |
| 279 | if (m68k_fputype & FPU_68881 && | 279 | if (m68k_fputype & FPU_68881 && |
| 280 | !(context_size == 0x18 || context_size == 0xb4)) | 280 | !(context_size == 0x18 || context_size == 0xb4)) |
| 281 | goto out; | 281 | goto out; |
| 282 | if (m68k_fputype & FPU_68882 && | 282 | if (m68k_fputype & FPU_68882 && |
| 283 | !(context_size == 0x38 || context_size == 0xd4)) | 283 | !(context_size == 0x38 || context_size == 0xd4)) |
| 284 | goto out; | 284 | goto out; |
| 285 | } else if (CPU_IS_040) { | 285 | } else if (CPU_IS_040) { |
| 286 | if (!(context_size == 0x00 || | 286 | if (!(context_size == 0x00 || |
| 287 | context_size == 0x28 || | 287 | context_size == 0x28 || |
| 288 | context_size == 0x60)) | 288 | context_size == 0x60)) |
| 289 | goto out; | 289 | goto out; |
| 290 | } else if (CPU_IS_060) { | 290 | } else if (CPU_IS_060) { |
| 291 | if (!(fpstate[3] == 0x00 || | 291 | if (!(fpstate[3] == 0x00 || |
| 292 | fpstate[3] == 0x60 || | 292 | fpstate[3] == 0x60 || |
| 293 | fpstate[3] == 0xe0)) | 293 | fpstate[3] == 0xe0)) |
| 294 | goto out; | 294 | goto out; |
| 295 | } else | 295 | } else |
| 296 | goto out; | 296 | goto out; |
| 297 | if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, | 297 | if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, |
| 298 | sizeof(fpregs))) | 298 | sizeof(fpregs))) |
| 299 | goto out; | 299 | goto out; |
| 300 | __asm__ volatile (".chip 68k/68881\n\t" | 300 | __asm__ volatile (".chip 68k/68881\n\t" |
| 301 | "fmovemx %0,%%fp0-%%fp7\n\t" | 301 | "fmovemx %0,%%fp0-%%fp7\n\t" |
| 302 | "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" | 302 | "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" |
| 303 | ".chip 68k" | 303 | ".chip 68k" |
| 304 | : /* no outputs */ | 304 | : /* no outputs */ |
| 305 | : "m" (*fpregs.f_fpregs), | 305 | : "m" (*fpregs.f_fpregs), |
| 306 | "m" (*fpregs.f_fpcntl)); | 306 | "m" (*fpregs.f_fpcntl)); |
| 307 | } | 307 | } |
| 308 | if (context_size && | 308 | if (context_size && |
| 309 | __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1, | 309 | __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1, |
| 310 | context_size)) | 310 | context_size)) |
| 311 | goto out; | 311 | goto out; |
| 312 | __asm__ volatile (".chip 68k/68881\n\t" | 312 | __asm__ volatile (".chip 68k/68881\n\t" |
| 313 | "frestore %0\n\t" | 313 | "frestore %0\n\t" |
| 314 | ".chip 68k" : : "m" (*fpstate)); | 314 | ".chip 68k" : : "m" (*fpstate)); |
| 315 | err = 0; | 315 | err = 0; |
| 316 | 316 | ||
| 317 | out: | 317 | out: |
| 318 | return err; | 318 | return err; |
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | static inline int | 321 | static inline int |
| 322 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp, | 322 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp, |
| 323 | int *pd0) | 323 | int *pd0) |
| 324 | { | 324 | { |
| 325 | int fsize, formatvec; | 325 | int fsize, formatvec; |
| 326 | struct sigcontext context; | 326 | struct sigcontext context; |
| 327 | int err; | 327 | int err; |
| 328 | 328 | ||
| 329 | /* get previous context */ | 329 | /* get previous context */ |
| 330 | if (copy_from_user(&context, usc, sizeof(context))) | 330 | if (copy_from_user(&context, usc, sizeof(context))) |
| 331 | goto badframe; | 331 | goto badframe; |
| 332 | 332 | ||
| 333 | /* restore passed registers */ | 333 | /* restore passed registers */ |
| 334 | regs->d1 = context.sc_d1; | 334 | regs->d1 = context.sc_d1; |
| 335 | regs->a0 = context.sc_a0; | 335 | regs->a0 = context.sc_a0; |
| 336 | regs->a1 = context.sc_a1; | 336 | regs->a1 = context.sc_a1; |
| 337 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); | 337 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); |
| 338 | regs->pc = context.sc_pc; | 338 | regs->pc = context.sc_pc; |
| 339 | regs->orig_d0 = -1; /* disable syscall checks */ | 339 | regs->orig_d0 = -1; /* disable syscall checks */ |
| 340 | wrusp(context.sc_usp); | 340 | wrusp(context.sc_usp); |
| 341 | formatvec = context.sc_formatvec; | 341 | formatvec = context.sc_formatvec; |
| 342 | regs->format = formatvec >> 12; | 342 | regs->format = formatvec >> 12; |
| 343 | regs->vector = formatvec & 0xfff; | 343 | regs->vector = formatvec & 0xfff; |
| 344 | 344 | ||
| 345 | err = restore_fpu_state(&context); | 345 | err = restore_fpu_state(&context); |
| 346 | 346 | ||
| 347 | fsize = frame_extra_sizes[regs->format]; | 347 | fsize = frame_extra_sizes[regs->format]; |
| 348 | if (fsize < 0) { | 348 | if (fsize < 0) { |
| 349 | /* | 349 | /* |
| 350 | * user process trying to return with weird frame format | 350 | * user process trying to return with weird frame format |
| 351 | */ | 351 | */ |
| 352 | #ifdef DEBUG | 352 | #ifdef DEBUG |
| 353 | printk("user process returning with weird frame format\n"); | 353 | printk("user process returning with weird frame format\n"); |
| 354 | #endif | 354 | #endif |
| 355 | goto badframe; | 355 | goto badframe; |
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | /* OK. Make room on the supervisor stack for the extra junk, | 358 | /* OK. Make room on the supervisor stack for the extra junk, |
| 359 | * if necessary. | 359 | * if necessary. |
| 360 | */ | 360 | */ |
| 361 | 361 | ||
| 362 | if (fsize) { | 362 | if (fsize) { |
| 363 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | 363 | struct switch_stack *sw = (struct switch_stack *)regs - 1; |
| 364 | regs->d0 = context.sc_d0; | 364 | regs->d0 = context.sc_d0; |
| 365 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) | 365 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) |
| 366 | __asm__ __volatile__ | 366 | __asm__ __volatile__ |
| 367 | (" movel %0,%/a0\n\t" | 367 | (" movel %0,%/a0\n\t" |
| 368 | " subl %1,%/a0\n\t" /* make room on stack */ | 368 | " subl %1,%/a0\n\t" /* make room on stack */ |
| 369 | " movel %/a0,%/sp\n\t" /* set stack pointer */ | 369 | " movel %/a0,%/sp\n\t" /* set stack pointer */ |
| 370 | /* move switch_stack and pt_regs */ | 370 | /* move switch_stack and pt_regs */ |
| 371 | "1: movel %0@+,%/a0@+\n\t" | 371 | "1: movel %0@+,%/a0@+\n\t" |
| 372 | " dbra %2,1b\n\t" | 372 | " dbra %2,1b\n\t" |
| 373 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ | 373 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ |
| 374 | " lsrl #2,%1\n\t" | 374 | " lsrl #2,%1\n\t" |
| 375 | " subql #1,%1\n\t" | 375 | " subql #1,%1\n\t" |
| 376 | "2: movesl %4@+,%2\n\t" | 376 | "2: movesl %4@+,%2\n\t" |
| 377 | "3: movel %2,%/a0@+\n\t" | 377 | "3: movel %2,%/a0@+\n\t" |
| 378 | " dbra %1,2b\n\t" | 378 | " dbra %1,2b\n\t" |
| 379 | " bral ret_from_signal\n" | 379 | " bral ret_from_signal\n" |
| 380 | "4:\n" | 380 | "4:\n" |
| 381 | ".section __ex_table,\"a\"\n" | 381 | ".section __ex_table,\"a\"\n" |
| 382 | " .align 4\n" | 382 | " .align 4\n" |
| 383 | " .long 2b,4b\n" | 383 | " .long 2b,4b\n" |
| 384 | " .long 3b,4b\n" | 384 | " .long 3b,4b\n" |
| 385 | ".previous" | 385 | ".previous" |
| 386 | : /* no outputs, it doesn't ever return */ | 386 | : /* no outputs, it doesn't ever return */ |
| 387 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), | 387 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), |
| 388 | "n" (frame_offset), "a" (fp) | 388 | "n" (frame_offset), "a" (fp) |
| 389 | : "a0"); | 389 | : "a0"); |
| 390 | #undef frame_offset | 390 | #undef frame_offset |
| 391 | /* | 391 | /* |
| 392 | * If we ever get here an exception occurred while | 392 | * If we ever get here an exception occurred while |
| 393 | * building the above stack-frame. | 393 | * building the above stack-frame. |
| 394 | */ | 394 | */ |
| 395 | goto badframe; | 395 | goto badframe; |
| 396 | } | 396 | } |
| 397 | 397 | ||
| 398 | *pd0 = context.sc_d0; | 398 | *pd0 = context.sc_d0; |
| 399 | return err; | 399 | return err; |
| 400 | 400 | ||
| 401 | badframe: | 401 | badframe: |
| 402 | return 1; | 402 | return 1; |
| 403 | } | 403 | } |
| 404 | 404 | ||
| 405 | static inline int | 405 | static inline int |
| 406 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, | 406 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, |
| 407 | struct ucontext __user *uc, int *pd0) | 407 | struct ucontext __user *uc, int *pd0) |
| 408 | { | 408 | { |
| 409 | int fsize, temp; | 409 | int fsize, temp; |
| 410 | greg_t __user *gregs = uc->uc_mcontext.gregs; | 410 | greg_t __user *gregs = uc->uc_mcontext.gregs; |
| 411 | unsigned long usp; | 411 | unsigned long usp; |
| 412 | int err; | 412 | int err; |
| 413 | 413 | ||
| 414 | err = __get_user(temp, &uc->uc_mcontext.version); | 414 | err = __get_user(temp, &uc->uc_mcontext.version); |
| 415 | if (temp != MCONTEXT_VERSION) | 415 | if (temp != MCONTEXT_VERSION) |
| 416 | goto badframe; | 416 | goto badframe; |
| 417 | /* restore passed registers */ | 417 | /* restore passed registers */ |
| 418 | err |= __get_user(regs->d0, &gregs[0]); | 418 | err |= __get_user(regs->d0, &gregs[0]); |
| 419 | err |= __get_user(regs->d1, &gregs[1]); | 419 | err |= __get_user(regs->d1, &gregs[1]); |
| 420 | err |= __get_user(regs->d2, &gregs[2]); | 420 | err |= __get_user(regs->d2, &gregs[2]); |
| 421 | err |= __get_user(regs->d3, &gregs[3]); | 421 | err |= __get_user(regs->d3, &gregs[3]); |
| 422 | err |= __get_user(regs->d4, &gregs[4]); | 422 | err |= __get_user(regs->d4, &gregs[4]); |
| 423 | err |= __get_user(regs->d5, &gregs[5]); | 423 | err |= __get_user(regs->d5, &gregs[5]); |
| 424 | err |= __get_user(sw->d6, &gregs[6]); | 424 | err |= __get_user(sw->d6, &gregs[6]); |
| 425 | err |= __get_user(sw->d7, &gregs[7]); | 425 | err |= __get_user(sw->d7, &gregs[7]); |
| 426 | err |= __get_user(regs->a0, &gregs[8]); | 426 | err |= __get_user(regs->a0, &gregs[8]); |
| 427 | err |= __get_user(regs->a1, &gregs[9]); | 427 | err |= __get_user(regs->a1, &gregs[9]); |
| 428 | err |= __get_user(regs->a2, &gregs[10]); | 428 | err |= __get_user(regs->a2, &gregs[10]); |
| 429 | err |= __get_user(sw->a3, &gregs[11]); | 429 | err |= __get_user(sw->a3, &gregs[11]); |
| 430 | err |= __get_user(sw->a4, &gregs[12]); | 430 | err |= __get_user(sw->a4, &gregs[12]); |
| 431 | err |= __get_user(sw->a5, &gregs[13]); | 431 | err |= __get_user(sw->a5, &gregs[13]); |
| 432 | err |= __get_user(sw->a6, &gregs[14]); | 432 | err |= __get_user(sw->a6, &gregs[14]); |
| 433 | err |= __get_user(usp, &gregs[15]); | 433 | err |= __get_user(usp, &gregs[15]); |
| 434 | wrusp(usp); | 434 | wrusp(usp); |
| 435 | err |= __get_user(regs->pc, &gregs[16]); | 435 | err |= __get_user(regs->pc, &gregs[16]); |
| 436 | err |= __get_user(temp, &gregs[17]); | 436 | err |= __get_user(temp, &gregs[17]); |
| 437 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); | 437 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); |
| 438 | regs->orig_d0 = -1; /* disable syscall checks */ | 438 | regs->orig_d0 = -1; /* disable syscall checks */ |
| 439 | err |= __get_user(temp, &uc->uc_formatvec); | 439 | err |= __get_user(temp, &uc->uc_formatvec); |
| 440 | regs->format = temp >> 12; | 440 | regs->format = temp >> 12; |
| 441 | regs->vector = temp & 0xfff; | 441 | regs->vector = temp & 0xfff; |
| 442 | 442 | ||
| 443 | err |= rt_restore_fpu_state(uc); | 443 | err |= rt_restore_fpu_state(uc); |
| 444 | 444 | ||
| 445 | if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) | 445 | if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) |
| 446 | goto badframe; | 446 | goto badframe; |
| 447 | 447 | ||
| 448 | fsize = frame_extra_sizes[regs->format]; | 448 | fsize = frame_extra_sizes[regs->format]; |
| 449 | if (fsize < 0) { | 449 | if (fsize < 0) { |
| 450 | /* | 450 | /* |
| 451 | * user process trying to return with weird frame format | 451 | * user process trying to return with weird frame format |
| 452 | */ | 452 | */ |
| 453 | #ifdef DEBUG | 453 | #ifdef DEBUG |
| 454 | printk("user process returning with weird frame format\n"); | 454 | printk("user process returning with weird frame format\n"); |
| 455 | #endif | 455 | #endif |
| 456 | goto badframe; | 456 | goto badframe; |
| 457 | } | 457 | } |
| 458 | 458 | ||
| 459 | /* OK. Make room on the supervisor stack for the extra junk, | 459 | /* OK. Make room on the supervisor stack for the extra junk, |
| 460 | * if necessary. | 460 | * if necessary. |
| 461 | */ | 461 | */ |
| 462 | 462 | ||
| 463 | if (fsize) { | 463 | if (fsize) { |
| 464 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) | 464 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) |
| 465 | __asm__ __volatile__ | 465 | __asm__ __volatile__ |
| 466 | (" movel %0,%/a0\n\t" | 466 | (" movel %0,%/a0\n\t" |
| 467 | " subl %1,%/a0\n\t" /* make room on stack */ | 467 | " subl %1,%/a0\n\t" /* make room on stack */ |
| 468 | " movel %/a0,%/sp\n\t" /* set stack pointer */ | 468 | " movel %/a0,%/sp\n\t" /* set stack pointer */ |
| 469 | /* move switch_stack and pt_regs */ | 469 | /* move switch_stack and pt_regs */ |
| 470 | "1: movel %0@+,%/a0@+\n\t" | 470 | "1: movel %0@+,%/a0@+\n\t" |
| 471 | " dbra %2,1b\n\t" | 471 | " dbra %2,1b\n\t" |
| 472 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ | 472 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ |
| 473 | " lsrl #2,%1\n\t" | 473 | " lsrl #2,%1\n\t" |
| 474 | " subql #1,%1\n\t" | 474 | " subql #1,%1\n\t" |
| 475 | "2: movesl %4@+,%2\n\t" | 475 | "2: movesl %4@+,%2\n\t" |
| 476 | "3: movel %2,%/a0@+\n\t" | 476 | "3: movel %2,%/a0@+\n\t" |
| 477 | " dbra %1,2b\n\t" | 477 | " dbra %1,2b\n\t" |
| 478 | " bral ret_from_signal\n" | 478 | " bral ret_from_signal\n" |
| 479 | "4:\n" | 479 | "4:\n" |
| 480 | ".section __ex_table,\"a\"\n" | 480 | ".section __ex_table,\"a\"\n" |
| 481 | " .align 4\n" | 481 | " .align 4\n" |
| 482 | " .long 2b,4b\n" | 482 | " .long 2b,4b\n" |
| 483 | " .long 3b,4b\n" | 483 | " .long 3b,4b\n" |
| 484 | ".previous" | 484 | ".previous" |
| 485 | : /* no outputs, it doesn't ever return */ | 485 | : /* no outputs, it doesn't ever return */ |
| 486 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), | 486 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), |
| 487 | "n" (frame_offset), "a" (&uc->uc_extra) | 487 | "n" (frame_offset), "a" (&uc->uc_extra) |
| 488 | : "a0"); | 488 | : "a0"); |
| 489 | #undef frame_offset | 489 | #undef frame_offset |
| 490 | /* | 490 | /* |
| 491 | * If we ever get here an exception occurred while | 491 | * If we ever get here an exception occurred while |
| 492 | * building the above stack-frame. | 492 | * building the above stack-frame. |
| 493 | */ | 493 | */ |
| 494 | goto badframe; | 494 | goto badframe; |
| 495 | } | 495 | } |
| 496 | 496 | ||
| 497 | *pd0 = regs->d0; | 497 | *pd0 = regs->d0; |
| 498 | return err; | 498 | return err; |
| 499 | 499 | ||
| 500 | badframe: | 500 | badframe: |
| 501 | return 1; | 501 | return 1; |
| 502 | } | 502 | } |
| 503 | 503 | ||
| 504 | asmlinkage int do_sigreturn(unsigned long __unused) | 504 | asmlinkage int do_sigreturn(unsigned long __unused) |
| 505 | { | 505 | { |
| 506 | struct switch_stack *sw = (struct switch_stack *) &__unused; | 506 | struct switch_stack *sw = (struct switch_stack *) &__unused; |
| 507 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | 507 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); |
| 508 | unsigned long usp = rdusp(); | 508 | unsigned long usp = rdusp(); |
| 509 | struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); | 509 | struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); |
| 510 | sigset_t set; | 510 | sigset_t set; |
| 511 | int d0; | 511 | int d0; |
| 512 | 512 | ||
| 513 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 513 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 514 | goto badframe; | 514 | goto badframe; |
| 515 | if (__get_user(set.sig[0], &frame->sc.sc_mask) || | 515 | if (__get_user(set.sig[0], &frame->sc.sc_mask) || |
| 516 | (_NSIG_WORDS > 1 && | 516 | (_NSIG_WORDS > 1 && |
| 517 | __copy_from_user(&set.sig[1], &frame->extramask, | 517 | __copy_from_user(&set.sig[1], &frame->extramask, |
| 518 | sizeof(frame->extramask)))) | 518 | sizeof(frame->extramask)))) |
| 519 | goto badframe; | 519 | goto badframe; |
| 520 | 520 | ||
| 521 | sigdelsetmask(&set, ~_BLOCKABLE); | 521 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 522 | current->blocked = set; | 522 | current->blocked = set; |
| 523 | recalc_sigpending(); | 523 | recalc_sigpending(); |
| 524 | 524 | ||
| 525 | if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) | 525 | if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) |
| 526 | goto badframe; | 526 | goto badframe; |
| 527 | return d0; | 527 | return d0; |
| 528 | 528 | ||
| 529 | badframe: | 529 | badframe: |
| 530 | force_sig(SIGSEGV, current); | 530 | force_sig(SIGSEGV, current); |
| 531 | return 0; | 531 | return 0; |
| 532 | } | 532 | } |
| 533 | 533 | ||
| 534 | asmlinkage int do_rt_sigreturn(unsigned long __unused) | 534 | asmlinkage int do_rt_sigreturn(unsigned long __unused) |
| 535 | { | 535 | { |
| 536 | struct switch_stack *sw = (struct switch_stack *) &__unused; | 536 | struct switch_stack *sw = (struct switch_stack *) &__unused; |
| 537 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | 537 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); |
| 538 | unsigned long usp = rdusp(); | 538 | unsigned long usp = rdusp(); |
| 539 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4); | 539 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4); |
| 540 | sigset_t set; | 540 | sigset_t set; |
| 541 | int d0; | 541 | int d0; |
| 542 | 542 | ||
| 543 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 543 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 544 | goto badframe; | 544 | goto badframe; |
| 545 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 545 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| 546 | goto badframe; | 546 | goto badframe; |
| 547 | 547 | ||
| 548 | sigdelsetmask(&set, ~_BLOCKABLE); | 548 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 549 | current->blocked = set; | 549 | current->blocked = set; |
| 550 | recalc_sigpending(); | 550 | recalc_sigpending(); |
| 551 | 551 | ||
| 552 | if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) | 552 | if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) |
| 553 | goto badframe; | 553 | goto badframe; |
| 554 | return d0; | 554 | return d0; |
| 555 | 555 | ||
| 556 | badframe: | 556 | badframe: |
| 557 | force_sig(SIGSEGV, current); | 557 | force_sig(SIGSEGV, current); |
| 558 | return 0; | 558 | return 0; |
| 559 | } | 559 | } |
| 560 | 560 | ||
| 561 | /* | 561 | /* |
| 562 | * Set up a signal frame. | 562 | * Set up a signal frame. |
| 563 | */ | 563 | */ |
| 564 | 564 | ||
| 565 | static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) | 565 | static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) |
| 566 | { | 566 | { |
| 567 | if (FPU_IS_EMU) { | 567 | if (FPU_IS_EMU) { |
| 568 | /* save registers */ | 568 | /* save registers */ |
| 569 | memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); | 569 | memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); |
| 570 | memcpy(sc->sc_fpregs, current->thread.fp, 24); | 570 | memcpy(sc->sc_fpregs, current->thread.fp, 24); |
| 571 | return; | 571 | return; |
| 572 | } | 572 | } |
| 573 | 573 | ||
| 574 | __asm__ volatile (".chip 68k/68881\n\t" | 574 | __asm__ volatile (".chip 68k/68881\n\t" |
| 575 | "fsave %0\n\t" | 575 | "fsave %0\n\t" |
| 576 | ".chip 68k" | 576 | ".chip 68k" |
| 577 | : : "m" (*sc->sc_fpstate) : "memory"); | 577 | : : "m" (*sc->sc_fpstate) : "memory"); |
| 578 | 578 | ||
| 579 | if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { | 579 | if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { |
| 580 | fpu_version = sc->sc_fpstate[0]; | 580 | fpu_version = sc->sc_fpstate[0]; |
| 581 | if (CPU_IS_020_OR_030 && | 581 | if (CPU_IS_020_OR_030 && |
| 582 | regs->vector >= (VEC_FPBRUC * 4) && | 582 | regs->vector >= (VEC_FPBRUC * 4) && |
| 583 | regs->vector <= (VEC_FPNAN * 4)) { | 583 | regs->vector <= (VEC_FPNAN * 4)) { |
| 584 | /* Clear pending exception in 68882 idle frame */ | 584 | /* Clear pending exception in 68882 idle frame */ |
| 585 | if (*(unsigned short *) sc->sc_fpstate == 0x1f38) | 585 | if (*(unsigned short *) sc->sc_fpstate == 0x1f38) |
| 586 | sc->sc_fpstate[0x38] |= 1 << 3; | 586 | sc->sc_fpstate[0x38] |= 1 << 3; |
| 587 | } | 587 | } |
| 588 | __asm__ volatile (".chip 68k/68881\n\t" | 588 | __asm__ volatile (".chip 68k/68881\n\t" |
| 589 | "fmovemx %%fp0-%%fp1,%0\n\t" | 589 | "fmovemx %%fp0-%%fp1,%0\n\t" |
| 590 | "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" | 590 | "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" |
| 591 | ".chip 68k" | 591 | ".chip 68k" |
| 592 | : "=m" (*sc->sc_fpregs), | 592 | : "=m" (*sc->sc_fpregs), |
| 593 | "=m" (*sc->sc_fpcntl) | 593 | "=m" (*sc->sc_fpcntl) |
| 594 | : /* no inputs */ | 594 | : /* no inputs */ |
| 595 | : "memory"); | 595 | : "memory"); |
| 596 | } | 596 | } |
| 597 | } | 597 | } |
| 598 | 598 | ||
| 599 | static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs) | 599 | static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs) |
| 600 | { | 600 | { |
| 601 | unsigned char fpstate[FPCONTEXT_SIZE]; | 601 | unsigned char fpstate[FPCONTEXT_SIZE]; |
| 602 | int context_size = CPU_IS_060 ? 8 : 0; | 602 | int context_size = CPU_IS_060 ? 8 : 0; |
| 603 | int err = 0; | 603 | int err = 0; |
| 604 | 604 | ||
| 605 | if (FPU_IS_EMU) { | 605 | if (FPU_IS_EMU) { |
| 606 | /* save fpu control register */ | 606 | /* save fpu control register */ |
| 607 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl, | 607 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl, |
| 608 | current->thread.fpcntl, 12); | 608 | current->thread.fpcntl, 12); |
| 609 | /* save all other fpu register */ | 609 | /* save all other fpu register */ |
| 610 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, | 610 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, |
| 611 | current->thread.fp, 96); | 611 | current->thread.fp, 96); |
| 612 | return err; | 612 | return err; |
| 613 | } | 613 | } |
| 614 | 614 | ||
| 615 | __asm__ volatile (".chip 68k/68881\n\t" | 615 | __asm__ volatile (".chip 68k/68881\n\t" |
| 616 | "fsave %0\n\t" | 616 | "fsave %0\n\t" |
| 617 | ".chip 68k" | 617 | ".chip 68k" |
| 618 | : : "m" (*fpstate) : "memory"); | 618 | : : "m" (*fpstate) : "memory"); |
| 619 | 619 | ||
| 620 | err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate); | 620 | err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate); |
| 621 | if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { | 621 | if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { |
| 622 | fpregset_t fpregs; | 622 | fpregset_t fpregs; |
| 623 | if (!CPU_IS_060) | 623 | if (!CPU_IS_060) |
| 624 | context_size = fpstate[1]; | 624 | context_size = fpstate[1]; |
| 625 | fpu_version = fpstate[0]; | 625 | fpu_version = fpstate[0]; |
| 626 | if (CPU_IS_020_OR_030 && | 626 | if (CPU_IS_020_OR_030 && |
| 627 | regs->vector >= (VEC_FPBRUC * 4) && | 627 | regs->vector >= (VEC_FPBRUC * 4) && |
| 628 | regs->vector <= (VEC_FPNAN * 4)) { | 628 | regs->vector <= (VEC_FPNAN * 4)) { |
| 629 | /* Clear pending exception in 68882 idle frame */ | 629 | /* Clear pending exception in 68882 idle frame */ |
| 630 | if (*(unsigned short *) fpstate == 0x1f38) | 630 | if (*(unsigned short *) fpstate == 0x1f38) |
| 631 | fpstate[0x38] |= 1 << 3; | 631 | fpstate[0x38] |= 1 << 3; |
| 632 | } | 632 | } |
| 633 | __asm__ volatile (".chip 68k/68881\n\t" | 633 | __asm__ volatile (".chip 68k/68881\n\t" |
| 634 | "fmovemx %%fp0-%%fp7,%0\n\t" | 634 | "fmovemx %%fp0-%%fp7,%0\n\t" |
| 635 | "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" | 635 | "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" |
| 636 | ".chip 68k" | 636 | ".chip 68k" |
| 637 | : "=m" (*fpregs.f_fpregs), | 637 | : "=m" (*fpregs.f_fpregs), |
| 638 | "=m" (*fpregs.f_fpcntl) | 638 | "=m" (*fpregs.f_fpcntl) |
| 639 | : /* no inputs */ | 639 | : /* no inputs */ |
| 640 | : "memory"); | 640 | : "memory"); |
| 641 | err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, | 641 | err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, |
| 642 | sizeof(fpregs)); | 642 | sizeof(fpregs)); |
| 643 | } | 643 | } |
| 644 | if (context_size) | 644 | if (context_size) |
| 645 | err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4, | 645 | err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4, |
| 646 | context_size); | 646 | context_size); |
| 647 | return err; | 647 | return err; |
| 648 | } | 648 | } |
| 649 | 649 | ||
| 650 | static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, | 650 | static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, |
| 651 | unsigned long mask) | 651 | unsigned long mask) |
| 652 | { | 652 | { |
| 653 | sc->sc_mask = mask; | 653 | sc->sc_mask = mask; |
| 654 | sc->sc_usp = rdusp(); | 654 | sc->sc_usp = rdusp(); |
| 655 | sc->sc_d0 = regs->d0; | 655 | sc->sc_d0 = regs->d0; |
| 656 | sc->sc_d1 = regs->d1; | 656 | sc->sc_d1 = regs->d1; |
| 657 | sc->sc_a0 = regs->a0; | 657 | sc->sc_a0 = regs->a0; |
| 658 | sc->sc_a1 = regs->a1; | 658 | sc->sc_a1 = regs->a1; |
| 659 | sc->sc_sr = regs->sr; | 659 | sc->sc_sr = regs->sr; |
| 660 | sc->sc_pc = regs->pc; | 660 | sc->sc_pc = regs->pc; |
| 661 | sc->sc_formatvec = regs->format << 12 | regs->vector; | 661 | sc->sc_formatvec = regs->format << 12 | regs->vector; |
| 662 | save_fpu_state(sc, regs); | 662 | save_fpu_state(sc, regs); |
| 663 | } | 663 | } |
| 664 | 664 | ||
| 665 | static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs) | 665 | static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs) |
| 666 | { | 666 | { |
| 667 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | 667 | struct switch_stack *sw = (struct switch_stack *)regs - 1; |
| 668 | greg_t __user *gregs = uc->uc_mcontext.gregs; | 668 | greg_t __user *gregs = uc->uc_mcontext.gregs; |
| 669 | int err = 0; | 669 | int err = 0; |
| 670 | 670 | ||
| 671 | err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); | 671 | err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); |
| 672 | err |= __put_user(regs->d0, &gregs[0]); | 672 | err |= __put_user(regs->d0, &gregs[0]); |
| 673 | err |= __put_user(regs->d1, &gregs[1]); | 673 | err |= __put_user(regs->d1, &gregs[1]); |
| 674 | err |= __put_user(regs->d2, &gregs[2]); | 674 | err |= __put_user(regs->d2, &gregs[2]); |
| 675 | err |= __put_user(regs->d3, &gregs[3]); | 675 | err |= __put_user(regs->d3, &gregs[3]); |
| 676 | err |= __put_user(regs->d4, &gregs[4]); | 676 | err |= __put_user(regs->d4, &gregs[4]); |
| 677 | err |= __put_user(regs->d5, &gregs[5]); | 677 | err |= __put_user(regs->d5, &gregs[5]); |
| 678 | err |= __put_user(sw->d6, &gregs[6]); | 678 | err |= __put_user(sw->d6, &gregs[6]); |
| 679 | err |= __put_user(sw->d7, &gregs[7]); | 679 | err |= __put_user(sw->d7, &gregs[7]); |
| 680 | err |= __put_user(regs->a0, &gregs[8]); | 680 | err |= __put_user(regs->a0, &gregs[8]); |
| 681 | err |= __put_user(regs->a1, &gregs[9]); | 681 | err |= __put_user(regs->a1, &gregs[9]); |
| 682 | err |= __put_user(regs->a2, &gregs[10]); | 682 | err |= __put_user(regs->a2, &gregs[10]); |
| 683 | err |= __put_user(sw->a3, &gregs[11]); | 683 | err |= __put_user(sw->a3, &gregs[11]); |
| 684 | err |= __put_user(sw->a4, &gregs[12]); | 684 | err |= __put_user(sw->a4, &gregs[12]); |
| 685 | err |= __put_user(sw->a5, &gregs[13]); | 685 | err |= __put_user(sw->a5, &gregs[13]); |
| 686 | err |= __put_user(sw->a6, &gregs[14]); | 686 | err |= __put_user(sw->a6, &gregs[14]); |
| 687 | err |= __put_user(rdusp(), &gregs[15]); | 687 | err |= __put_user(rdusp(), &gregs[15]); |
| 688 | err |= __put_user(regs->pc, &gregs[16]); | 688 | err |= __put_user(regs->pc, &gregs[16]); |
| 689 | err |= __put_user(regs->sr, &gregs[17]); | 689 | err |= __put_user(regs->sr, &gregs[17]); |
| 690 | err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec); | 690 | err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec); |
| 691 | err |= rt_save_fpu_state(uc, regs); | 691 | err |= rt_save_fpu_state(uc, regs); |
| 692 | return err; | 692 | return err; |
| 693 | } | 693 | } |
| 694 | 694 | ||
| 695 | static inline void push_cache (unsigned long vaddr) | 695 | static inline void push_cache (unsigned long vaddr) |
| 696 | { | 696 | { |
| 697 | /* | 697 | /* |
| 698 | * Using the old cache_push_v() was really a big waste. | 698 | * Using the old cache_push_v() was really a big waste. |
| 699 | * | 699 | * |
| 700 | * What we are trying to do is to flush 8 bytes to ram. | 700 | * What we are trying to do is to flush 8 bytes to ram. |
| 701 | * Flushing 2 cache lines of 16 bytes is much cheaper than | 701 | * Flushing 2 cache lines of 16 bytes is much cheaper than |
| 702 | * flushing 1 or 2 pages, as previously done in | 702 | * flushing 1 or 2 pages, as previously done in |
| 703 | * cache_push_v(). | 703 | * cache_push_v(). |
| 704 | * Jes | 704 | * Jes |
| 705 | */ | 705 | */ |
| 706 | if (CPU_IS_040) { | 706 | if (CPU_IS_040) { |
| 707 | unsigned long temp; | 707 | unsigned long temp; |
| 708 | 708 | ||
| 709 | __asm__ __volatile__ (".chip 68040\n\t" | 709 | __asm__ __volatile__ (".chip 68040\n\t" |
| 710 | "nop\n\t" | 710 | "nop\n\t" |
| 711 | "ptestr (%1)\n\t" | 711 | "ptestr (%1)\n\t" |
| 712 | "movec %%mmusr,%0\n\t" | 712 | "movec %%mmusr,%0\n\t" |
| 713 | ".chip 68k" | 713 | ".chip 68k" |
| 714 | : "=r" (temp) | 714 | : "=r" (temp) |
| 715 | : "a" (vaddr)); | 715 | : "a" (vaddr)); |
| 716 | 716 | ||
| 717 | temp &= PAGE_MASK; | 717 | temp &= PAGE_MASK; |
| 718 | temp |= vaddr & ~PAGE_MASK; | 718 | temp |= vaddr & ~PAGE_MASK; |
| 719 | 719 | ||
| 720 | __asm__ __volatile__ (".chip 68040\n\t" | 720 | __asm__ __volatile__ (".chip 68040\n\t" |
| 721 | "nop\n\t" | 721 | "nop\n\t" |
| 722 | "cpushl %%bc,(%0)\n\t" | 722 | "cpushl %%bc,(%0)\n\t" |
| 723 | ".chip 68k" | 723 | ".chip 68k" |
| 724 | : : "a" (temp)); | 724 | : : "a" (temp)); |
| 725 | } | 725 | } |
| 726 | else if (CPU_IS_060) { | 726 | else if (CPU_IS_060) { |
| 727 | unsigned long temp; | 727 | unsigned long temp; |
| 728 | __asm__ __volatile__ (".chip 68060\n\t" | 728 | __asm__ __volatile__ (".chip 68060\n\t" |
| 729 | "plpar (%0)\n\t" | 729 | "plpar (%0)\n\t" |
| 730 | ".chip 68k" | 730 | ".chip 68k" |
| 731 | : "=a" (temp) | 731 | : "=a" (temp) |
| 732 | : "0" (vaddr)); | 732 | : "0" (vaddr)); |
| 733 | __asm__ __volatile__ (".chip 68060\n\t" | 733 | __asm__ __volatile__ (".chip 68060\n\t" |
| 734 | "cpushl %%bc,(%0)\n\t" | 734 | "cpushl %%bc,(%0)\n\t" |
| 735 | ".chip 68k" | 735 | ".chip 68k" |
| 736 | : : "a" (temp)); | 736 | : : "a" (temp)); |
| 737 | } | 737 | } |
| 738 | else { | 738 | else { |
| 739 | /* | 739 | /* |
| 740 | * 68030/68020 have no writeback cache; | 740 | * 68030/68020 have no writeback cache; |
| 741 | * still need to clear icache. | 741 | * still need to clear icache. |
| 742 | * Note that vaddr is guaranteed to be long word aligned. | 742 | * Note that vaddr is guaranteed to be long word aligned. |
| 743 | */ | 743 | */ |
| 744 | unsigned long temp; | 744 | unsigned long temp; |
| 745 | asm volatile ("movec %%cacr,%0" : "=r" (temp)); | 745 | asm volatile ("movec %%cacr,%0" : "=r" (temp)); |
| 746 | temp += 4; | 746 | temp += 4; |
| 747 | asm volatile ("movec %0,%%caar\n\t" | 747 | asm volatile ("movec %0,%%caar\n\t" |
| 748 | "movec %1,%%cacr" | 748 | "movec %1,%%cacr" |
| 749 | : : "r" (vaddr), "r" (temp)); | 749 | : : "r" (vaddr), "r" (temp)); |
| 750 | asm volatile ("movec %0,%%caar\n\t" | 750 | asm volatile ("movec %0,%%caar\n\t" |
| 751 | "movec %1,%%cacr" | 751 | "movec %1,%%cacr" |
| 752 | : : "r" (vaddr + 4), "r" (temp)); | 752 | : : "r" (vaddr + 4), "r" (temp)); |
| 753 | } | 753 | } |
| 754 | } | 754 | } |
| 755 | 755 | ||
| 756 | static inline void __user * | 756 | static inline void __user * |
| 757 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 757 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) |
| 758 | { | 758 | { |
| 759 | unsigned long usp; | 759 | unsigned long usp; |
| 760 | 760 | ||
| 761 | /* Default to using normal stack. */ | 761 | /* Default to using normal stack. */ |
| 762 | usp = rdusp(); | 762 | usp = rdusp(); |
| 763 | 763 | ||
| 764 | /* This is the X/Open sanctioned signal stack switching. */ | 764 | /* This is the X/Open sanctioned signal stack switching. */ |
| 765 | if (ka->sa.sa_flags & SA_ONSTACK) { | 765 | if (ka->sa.sa_flags & SA_ONSTACK) { |
| 766 | if (!on_sig_stack(usp)) | 766 | if (!sas_ss_flags(usp)) |
| 767 | usp = current->sas_ss_sp + current->sas_ss_size; | 767 | usp = current->sas_ss_sp + current->sas_ss_size; |
| 768 | } | 768 | } |
| 769 | return (void __user *)((usp - frame_size) & -8UL); | 769 | return (void __user *)((usp - frame_size) & -8UL); |
| 770 | } | 770 | } |
| 771 | 771 | ||
| 772 | static void setup_frame (int sig, struct k_sigaction *ka, | 772 | static void setup_frame (int sig, struct k_sigaction *ka, |
| 773 | sigset_t *set, struct pt_regs *regs) | 773 | sigset_t *set, struct pt_regs *regs) |
| 774 | { | 774 | { |
| 775 | struct sigframe __user *frame; | 775 | struct sigframe __user *frame; |
| 776 | int fsize = frame_extra_sizes[regs->format]; | 776 | int fsize = frame_extra_sizes[regs->format]; |
| 777 | struct sigcontext context; | 777 | struct sigcontext context; |
| 778 | int err = 0; | 778 | int err = 0; |
| 779 | 779 | ||
| 780 | if (fsize < 0) { | 780 | if (fsize < 0) { |
| 781 | #ifdef DEBUG | 781 | #ifdef DEBUG |
| 782 | printk ("setup_frame: Unknown frame format %#x\n", | 782 | printk ("setup_frame: Unknown frame format %#x\n", |
| 783 | regs->format); | 783 | regs->format); |
| 784 | #endif | 784 | #endif |
| 785 | goto give_sigsegv; | 785 | goto give_sigsegv; |
| 786 | } | 786 | } |
| 787 | 787 | ||
| 788 | frame = get_sigframe(ka, regs, sizeof(*frame) + fsize); | 788 | frame = get_sigframe(ka, regs, sizeof(*frame) + fsize); |
| 789 | 789 | ||
| 790 | if (fsize) { | 790 | if (fsize) { |
| 791 | err |= copy_to_user (frame + 1, regs + 1, fsize); | 791 | err |= copy_to_user (frame + 1, regs + 1, fsize); |
| 792 | regs->stkadj = fsize; | 792 | regs->stkadj = fsize; |
| 793 | } | 793 | } |
| 794 | 794 | ||
| 795 | err |= __put_user((current_thread_info()->exec_domain | 795 | err |= __put_user((current_thread_info()->exec_domain |
| 796 | && current_thread_info()->exec_domain->signal_invmap | 796 | && current_thread_info()->exec_domain->signal_invmap |
| 797 | && sig < 32 | 797 | && sig < 32 |
| 798 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 798 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 799 | : sig), | 799 | : sig), |
| 800 | &frame->sig); | 800 | &frame->sig); |
| 801 | 801 | ||
| 802 | err |= __put_user(regs->vector, &frame->code); | 802 | err |= __put_user(regs->vector, &frame->code); |
| 803 | err |= __put_user(&frame->sc, &frame->psc); | 803 | err |= __put_user(&frame->sc, &frame->psc); |
| 804 | 804 | ||
| 805 | if (_NSIG_WORDS > 1) | 805 | if (_NSIG_WORDS > 1) |
| 806 | err |= copy_to_user(frame->extramask, &set->sig[1], | 806 | err |= copy_to_user(frame->extramask, &set->sig[1], |
| 807 | sizeof(frame->extramask)); | 807 | sizeof(frame->extramask)); |
| 808 | 808 | ||
| 809 | setup_sigcontext(&context, regs, set->sig[0]); | 809 | setup_sigcontext(&context, regs, set->sig[0]); |
| 810 | err |= copy_to_user (&frame->sc, &context, sizeof(context)); | 810 | err |= copy_to_user (&frame->sc, &context, sizeof(context)); |
| 811 | 811 | ||
| 812 | /* Set up to return from userspace. */ | 812 | /* Set up to return from userspace. */ |
| 813 | err |= __put_user(frame->retcode, &frame->pretcode); | 813 | err |= __put_user(frame->retcode, &frame->pretcode); |
| 814 | /* moveq #,d0; trap #0 */ | 814 | /* moveq #,d0; trap #0 */ |
| 815 | err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), | 815 | err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), |
| 816 | (long __user *)(frame->retcode)); | 816 | (long __user *)(frame->retcode)); |
| 817 | 817 | ||
| 818 | if (err) | 818 | if (err) |
| 819 | goto give_sigsegv; | 819 | goto give_sigsegv; |
| 820 | 820 | ||
| 821 | push_cache ((unsigned long) &frame->retcode); | 821 | push_cache ((unsigned long) &frame->retcode); |
| 822 | 822 | ||
| 823 | /* Set up registers for signal handler */ | 823 | /* Set up registers for signal handler */ |
| 824 | wrusp ((unsigned long) frame); | 824 | wrusp ((unsigned long) frame); |
| 825 | regs->pc = (unsigned long) ka->sa.sa_handler; | 825 | regs->pc = (unsigned long) ka->sa.sa_handler; |
| 826 | 826 | ||
| 827 | adjust_stack: | 827 | adjust_stack: |
| 828 | /* Prepare to skip over the extra stuff in the exception frame. */ | 828 | /* Prepare to skip over the extra stuff in the exception frame. */ |
| 829 | if (regs->stkadj) { | 829 | if (regs->stkadj) { |
| 830 | struct pt_regs *tregs = | 830 | struct pt_regs *tregs = |
| 831 | (struct pt_regs *)((ulong)regs + regs->stkadj); | 831 | (struct pt_regs *)((ulong)regs + regs->stkadj); |
| 832 | #ifdef DEBUG | 832 | #ifdef DEBUG |
| 833 | printk("Performing stackadjust=%04x\n", regs->stkadj); | 833 | printk("Performing stackadjust=%04x\n", regs->stkadj); |
| 834 | #endif | 834 | #endif |
| 835 | /* This must be copied with decreasing addresses to | 835 | /* This must be copied with decreasing addresses to |
| 836 | handle overlaps. */ | 836 | handle overlaps. */ |
| 837 | tregs->vector = 0; | 837 | tregs->vector = 0; |
| 838 | tregs->format = 0; | 838 | tregs->format = 0; |
| 839 | tregs->pc = regs->pc; | 839 | tregs->pc = regs->pc; |
| 840 | tregs->sr = regs->sr; | 840 | tregs->sr = regs->sr; |
| 841 | } | 841 | } |
| 842 | return; | 842 | return; |
| 843 | 843 | ||
| 844 | give_sigsegv: | 844 | give_sigsegv: |
| 845 | force_sigsegv(sig, current); | 845 | force_sigsegv(sig, current); |
| 846 | goto adjust_stack; | 846 | goto adjust_stack; |
| 847 | } | 847 | } |
| 848 | 848 | ||
| 849 | static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | 849 | static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, |
| 850 | sigset_t *set, struct pt_regs *regs) | 850 | sigset_t *set, struct pt_regs *regs) |
| 851 | { | 851 | { |
| 852 | struct rt_sigframe __user *frame; | 852 | struct rt_sigframe __user *frame; |
| 853 | int fsize = frame_extra_sizes[regs->format]; | 853 | int fsize = frame_extra_sizes[regs->format]; |
| 854 | int err = 0; | 854 | int err = 0; |
| 855 | 855 | ||
| 856 | if (fsize < 0) { | 856 | if (fsize < 0) { |
| 857 | #ifdef DEBUG | 857 | #ifdef DEBUG |
| 858 | printk ("setup_frame: Unknown frame format %#x\n", | 858 | printk ("setup_frame: Unknown frame format %#x\n", |
| 859 | regs->format); | 859 | regs->format); |
| 860 | #endif | 860 | #endif |
| 861 | goto give_sigsegv; | 861 | goto give_sigsegv; |
| 862 | } | 862 | } |
| 863 | 863 | ||
| 864 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 864 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
| 865 | 865 | ||
| 866 | if (fsize) { | 866 | if (fsize) { |
| 867 | err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize); | 867 | err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize); |
| 868 | regs->stkadj = fsize; | 868 | regs->stkadj = fsize; |
| 869 | } | 869 | } |
| 870 | 870 | ||
| 871 | err |= __put_user((current_thread_info()->exec_domain | 871 | err |= __put_user((current_thread_info()->exec_domain |
| 872 | && current_thread_info()->exec_domain->signal_invmap | 872 | && current_thread_info()->exec_domain->signal_invmap |
| 873 | && sig < 32 | 873 | && sig < 32 |
| 874 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 874 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 875 | : sig), | 875 | : sig), |
| 876 | &frame->sig); | 876 | &frame->sig); |
| 877 | err |= __put_user(&frame->info, &frame->pinfo); | 877 | err |= __put_user(&frame->info, &frame->pinfo); |
| 878 | err |= __put_user(&frame->uc, &frame->puc); | 878 | err |= __put_user(&frame->uc, &frame->puc); |
| 879 | err |= copy_siginfo_to_user(&frame->info, info); | 879 | err |= copy_siginfo_to_user(&frame->info, info); |
| 880 | 880 | ||
| 881 | /* Create the ucontext. */ | 881 | /* Create the ucontext. */ |
| 882 | err |= __put_user(0, &frame->uc.uc_flags); | 882 | err |= __put_user(0, &frame->uc.uc_flags); |
| 883 | err |= __put_user(NULL, &frame->uc.uc_link); | 883 | err |= __put_user(NULL, &frame->uc.uc_link); |
| 884 | err |= __put_user((void __user *)current->sas_ss_sp, | 884 | err |= __put_user((void __user *)current->sas_ss_sp, |
| 885 | &frame->uc.uc_stack.ss_sp); | 885 | &frame->uc.uc_stack.ss_sp); |
| 886 | err |= __put_user(sas_ss_flags(rdusp()), | 886 | err |= __put_user(sas_ss_flags(rdusp()), |
| 887 | &frame->uc.uc_stack.ss_flags); | 887 | &frame->uc.uc_stack.ss_flags); |
| 888 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 888 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
| 889 | err |= rt_setup_ucontext(&frame->uc, regs); | 889 | err |= rt_setup_ucontext(&frame->uc, regs); |
| 890 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); | 890 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 891 | 891 | ||
| 892 | /* Set up to return from userspace. */ | 892 | /* Set up to return from userspace. */ |
| 893 | err |= __put_user(frame->retcode, &frame->pretcode); | 893 | err |= __put_user(frame->retcode, &frame->pretcode); |
| 894 | /* moveq #,d0; notb d0; trap #0 */ | 894 | /* moveq #,d0; notb d0; trap #0 */ |
| 895 | err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), | 895 | err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), |
| 896 | (long __user *)(frame->retcode + 0)); | 896 | (long __user *)(frame->retcode + 0)); |
| 897 | err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4)); | 897 | err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4)); |
| 898 | 898 | ||
| 899 | if (err) | 899 | if (err) |
| 900 | goto give_sigsegv; | 900 | goto give_sigsegv; |
| 901 | 901 | ||
| 902 | push_cache ((unsigned long) &frame->retcode); | 902 | push_cache ((unsigned long) &frame->retcode); |
| 903 | 903 | ||
| 904 | /* Set up registers for signal handler */ | 904 | /* Set up registers for signal handler */ |
| 905 | wrusp ((unsigned long) frame); | 905 | wrusp ((unsigned long) frame); |
| 906 | regs->pc = (unsigned long) ka->sa.sa_handler; | 906 | regs->pc = (unsigned long) ka->sa.sa_handler; |
| 907 | 907 | ||
| 908 | adjust_stack: | 908 | adjust_stack: |
| 909 | /* Prepare to skip over the extra stuff in the exception frame. */ | 909 | /* Prepare to skip over the extra stuff in the exception frame. */ |
| 910 | if (regs->stkadj) { | 910 | if (regs->stkadj) { |
| 911 | struct pt_regs *tregs = | 911 | struct pt_regs *tregs = |
| 912 | (struct pt_regs *)((ulong)regs + regs->stkadj); | 912 | (struct pt_regs *)((ulong)regs + regs->stkadj); |
| 913 | #ifdef DEBUG | 913 | #ifdef DEBUG |
| 914 | printk("Performing stackadjust=%04x\n", regs->stkadj); | 914 | printk("Performing stackadjust=%04x\n", regs->stkadj); |
| 915 | #endif | 915 | #endif |
| 916 | /* This must be copied with decreasing addresses to | 916 | /* This must be copied with decreasing addresses to |
| 917 | handle overlaps. */ | 917 | handle overlaps. */ |
| 918 | tregs->vector = 0; | 918 | tregs->vector = 0; |
| 919 | tregs->format = 0; | 919 | tregs->format = 0; |
| 920 | tregs->pc = regs->pc; | 920 | tregs->pc = regs->pc; |
| 921 | tregs->sr = regs->sr; | 921 | tregs->sr = regs->sr; |
| 922 | } | 922 | } |
| 923 | return; | 923 | return; |
| 924 | 924 | ||
| 925 | give_sigsegv: | 925 | give_sigsegv: |
| 926 | force_sigsegv(sig, current); | 926 | force_sigsegv(sig, current); |
| 927 | goto adjust_stack; | 927 | goto adjust_stack; |
| 928 | } | 928 | } |
| 929 | 929 | ||
| 930 | static inline void | 930 | static inline void |
| 931 | handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) | 931 | handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) |
| 932 | { | 932 | { |
| 933 | switch (regs->d0) { | 933 | switch (regs->d0) { |
| 934 | case -ERESTARTNOHAND: | 934 | case -ERESTARTNOHAND: |
| 935 | if (!has_handler) | 935 | if (!has_handler) |
| 936 | goto do_restart; | 936 | goto do_restart; |
| 937 | regs->d0 = -EINTR; | 937 | regs->d0 = -EINTR; |
| 938 | break; | 938 | break; |
| 939 | 939 | ||
| 940 | case -ERESTARTSYS: | 940 | case -ERESTARTSYS: |
| 941 | if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { | 941 | if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { |
| 942 | regs->d0 = -EINTR; | 942 | regs->d0 = -EINTR; |
| 943 | break; | 943 | break; |
| 944 | } | 944 | } |
| 945 | /* fallthrough */ | 945 | /* fallthrough */ |
| 946 | case -ERESTARTNOINTR: | 946 | case -ERESTARTNOINTR: |
| 947 | do_restart: | 947 | do_restart: |
| 948 | regs->d0 = regs->orig_d0; | 948 | regs->d0 = regs->orig_d0; |
| 949 | regs->pc -= 2; | 949 | regs->pc -= 2; |
| 950 | break; | 950 | break; |
| 951 | } | 951 | } |
| 952 | } | 952 | } |
| 953 | 953 | ||
| 954 | void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) | 954 | void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) |
| 955 | { | 955 | { |
| 956 | if (regs->orig_d0 < 0) | 956 | if (regs->orig_d0 < 0) |
| 957 | return; | 957 | return; |
| 958 | switch (regs->d0) { | 958 | switch (regs->d0) { |
| 959 | case -ERESTARTNOHAND: | 959 | case -ERESTARTNOHAND: |
| 960 | case -ERESTARTSYS: | 960 | case -ERESTARTSYS: |
| 961 | case -ERESTARTNOINTR: | 961 | case -ERESTARTNOINTR: |
| 962 | regs->d0 = regs->orig_d0; | 962 | regs->d0 = regs->orig_d0; |
| 963 | regs->orig_d0 = -1; | 963 | regs->orig_d0 = -1; |
| 964 | regs->pc -= 2; | 964 | regs->pc -= 2; |
| 965 | break; | 965 | break; |
| 966 | } | 966 | } |
| 967 | } | 967 | } |
| 968 | 968 | ||
| 969 | /* | 969 | /* |
| 970 | * OK, we're invoking a handler | 970 | * OK, we're invoking a handler |
| 971 | */ | 971 | */ |
| 972 | static void | 972 | static void |
| 973 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | 973 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 974 | sigset_t *oldset, struct pt_regs *regs) | 974 | sigset_t *oldset, struct pt_regs *regs) |
| 975 | { | 975 | { |
| 976 | /* are we from a system call? */ | 976 | /* are we from a system call? */ |
| 977 | if (regs->orig_d0 >= 0) | 977 | if (regs->orig_d0 >= 0) |
| 978 | /* If so, check system call restarting.. */ | 978 | /* If so, check system call restarting.. */ |
| 979 | handle_restart(regs, ka, 1); | 979 | handle_restart(regs, ka, 1); |
| 980 | 980 | ||
| 981 | /* set up the stack frame */ | 981 | /* set up the stack frame */ |
| 982 | if (ka->sa.sa_flags & SA_SIGINFO) | 982 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 983 | setup_rt_frame(sig, ka, info, oldset, regs); | 983 | setup_rt_frame(sig, ka, info, oldset, regs); |
| 984 | else | 984 | else |
| 985 | setup_frame(sig, ka, oldset, regs); | 985 | setup_frame(sig, ka, oldset, regs); |
| 986 | 986 | ||
| 987 | if (ka->sa.sa_flags & SA_ONESHOT) | 987 | if (ka->sa.sa_flags & SA_ONESHOT) |
| 988 | ka->sa.sa_handler = SIG_DFL; | 988 | ka->sa.sa_handler = SIG_DFL; |
| 989 | 989 | ||
| 990 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 990 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
| 991 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 991 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 992 | sigaddset(¤t->blocked,sig); | 992 | sigaddset(¤t->blocked,sig); |
| 993 | recalc_sigpending(); | 993 | recalc_sigpending(); |
| 994 | } | 994 | } |
| 995 | 995 | ||
| 996 | /* | 996 | /* |
| 997 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 997 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 998 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 998 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 999 | * mistake. | 999 | * mistake. |
| 1000 | */ | 1000 | */ |
| 1001 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) | 1001 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) |
| 1002 | { | 1002 | { |
| 1003 | siginfo_t info; | 1003 | siginfo_t info; |
| 1004 | struct k_sigaction ka; | 1004 | struct k_sigaction ka; |
| 1005 | int signr; | 1005 | int signr; |
| 1006 | 1006 | ||
| 1007 | current->thread.esp0 = (unsigned long) regs; | 1007 | current->thread.esp0 = (unsigned long) regs; |
| 1008 | 1008 | ||
| 1009 | if (!oldset) | 1009 | if (!oldset) |
| 1010 | oldset = ¤t->blocked; | 1010 | oldset = ¤t->blocked; |
| 1011 | 1011 | ||
| 1012 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 1012 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 1013 | if (signr > 0) { | 1013 | if (signr > 0) { |
| 1014 | /* Whee! Actually deliver the signal. */ | 1014 | /* Whee! Actually deliver the signal. */ |
| 1015 | handle_signal(signr, &ka, &info, oldset, regs); | 1015 | handle_signal(signr, &ka, &info, oldset, regs); |
| 1016 | return 1; | 1016 | return 1; |
| 1017 | } | 1017 | } |
| 1018 | 1018 | ||
| 1019 | /* Did we come from a system call? */ | 1019 | /* Did we come from a system call? */ |
| 1020 | if (regs->orig_d0 >= 0) | 1020 | if (regs->orig_d0 >= 0) |
| 1021 | /* Restart the system call - no handlers present */ | 1021 | /* Restart the system call - no handlers present */ |
| 1022 | handle_restart(regs, NULL, 0); | 1022 | handle_restart(regs, NULL, 0); |
| 1023 | 1023 | ||
| 1024 | return 0; | 1024 | return 0; |
| 1025 | } | 1025 | } |
| 1026 | 1026 |
arch/m68knommu/kernel/signal.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/m68knommu/kernel/signal.c | 2 | * linux/arch/m68knommu/kernel/signal.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1991, 1992 Linus Torvalds | 4 | * Copyright (C) 1991, 1992 Linus Torvalds |
| 5 | * | 5 | * |
| 6 | * This file is subject to the terms and conditions of the GNU General Public | 6 | * This file is subject to the terms and conditions of the GNU General Public |
| 7 | * License. See the file COPYING in the main directory of this archive | 7 | * License. See the file COPYING in the main directory of this archive |
| 8 | * for more details. | 8 | * for more details. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | /* | 11 | /* |
| 12 | * Linux/m68k support by Hamish Macdonald | 12 | * Linux/m68k support by Hamish Macdonald |
| 13 | * | 13 | * |
| 14 | * 68060 fixes by Jesper Skov | 14 | * 68060 fixes by Jesper Skov |
| 15 | * | 15 | * |
| 16 | * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab | 16 | * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab |
| 17 | * | 17 | * |
| 18 | * mathemu support by Roman Zippel | 18 | * mathemu support by Roman Zippel |
| 19 | * (Note: fpstate in the signal context is completely ignored for the emulator | 19 | * (Note: fpstate in the signal context is completely ignored for the emulator |
| 20 | * and the internal floating point format is put on stack) | 20 | * and the internal floating point format is put on stack) |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | /* | 23 | /* |
| 24 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on | 24 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on |
| 25 | * Atari :-) Current limitation: Only one sigstack can be active at one time. | 25 | * Atari :-) Current limitation: Only one sigstack can be active at one time. |
| 26 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, | 26 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, |
| 27 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested | 27 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested |
| 28 | * signal handlers! | 28 | * signal handlers! |
| 29 | */ | 29 | */ |
| 30 | 30 | ||
| 31 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
| 32 | #include <linux/mm.h> | 32 | #include <linux/mm.h> |
| 33 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
| 34 | #include <linux/signal.h> | 34 | #include <linux/signal.h> |
| 35 | #include <linux/syscalls.h> | 35 | #include <linux/syscalls.h> |
| 36 | #include <linux/errno.h> | 36 | #include <linux/errno.h> |
| 37 | #include <linux/wait.h> | 37 | #include <linux/wait.h> |
| 38 | #include <linux/ptrace.h> | 38 | #include <linux/ptrace.h> |
| 39 | #include <linux/unistd.h> | 39 | #include <linux/unistd.h> |
| 40 | #include <linux/stddef.h> | 40 | #include <linux/stddef.h> |
| 41 | #include <linux/highuid.h> | 41 | #include <linux/highuid.h> |
| 42 | #include <linux/tty.h> | 42 | #include <linux/tty.h> |
| 43 | #include <linux/personality.h> | 43 | #include <linux/personality.h> |
| 44 | #include <linux/binfmts.h> | 44 | #include <linux/binfmts.h> |
| 45 | 45 | ||
| 46 | #include <asm/setup.h> | 46 | #include <asm/setup.h> |
| 47 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
| 48 | #include <asm/pgtable.h> | 48 | #include <asm/pgtable.h> |
| 49 | #include <asm/traps.h> | 49 | #include <asm/traps.h> |
| 50 | #include <asm/ucontext.h> | 50 | #include <asm/ucontext.h> |
| 51 | 51 | ||
| 52 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 52 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 53 | 53 | ||
| 54 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); | 54 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); |
| 55 | 55 | ||
| 56 | /* | 56 | /* |
| 57 | * Atomically swap in the new signal mask, and wait for a signal. | 57 | * Atomically swap in the new signal mask, and wait for a signal. |
| 58 | */ | 58 | */ |
| 59 | asmlinkage int do_sigsuspend(struct pt_regs *regs) | 59 | asmlinkage int do_sigsuspend(struct pt_regs *regs) |
| 60 | { | 60 | { |
| 61 | old_sigset_t mask = regs->d3; | 61 | old_sigset_t mask = regs->d3; |
| 62 | sigset_t saveset; | 62 | sigset_t saveset; |
| 63 | 63 | ||
| 64 | mask &= _BLOCKABLE; | 64 | mask &= _BLOCKABLE; |
| 65 | spin_lock_irq(¤t->sighand->siglock); | 65 | spin_lock_irq(¤t->sighand->siglock); |
| 66 | saveset = current->blocked; | 66 | saveset = current->blocked; |
| 67 | siginitset(¤t->blocked, mask); | 67 | siginitset(¤t->blocked, mask); |
| 68 | recalc_sigpending(); | 68 | recalc_sigpending(); |
| 69 | spin_unlock_irq(¤t->sighand->siglock); | 69 | spin_unlock_irq(¤t->sighand->siglock); |
| 70 | 70 | ||
| 71 | regs->d0 = -EINTR; | 71 | regs->d0 = -EINTR; |
| 72 | while (1) { | 72 | while (1) { |
| 73 | current->state = TASK_INTERRUPTIBLE; | 73 | current->state = TASK_INTERRUPTIBLE; |
| 74 | schedule(); | 74 | schedule(); |
| 75 | if (do_signal(&saveset, regs)) | 75 | if (do_signal(&saveset, regs)) |
| 76 | return -EINTR; | 76 | return -EINTR; |
| 77 | } | 77 | } |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | asmlinkage int | 80 | asmlinkage int |
| 81 | do_rt_sigsuspend(struct pt_regs *regs) | 81 | do_rt_sigsuspend(struct pt_regs *regs) |
| 82 | { | 82 | { |
| 83 | sigset_t *unewset = (sigset_t *)regs->d1; | 83 | sigset_t *unewset = (sigset_t *)regs->d1; |
| 84 | size_t sigsetsize = (size_t)regs->d2; | 84 | size_t sigsetsize = (size_t)regs->d2; |
| 85 | sigset_t saveset, newset; | 85 | sigset_t saveset, newset; |
| 86 | 86 | ||
| 87 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 87 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
| 88 | if (sigsetsize != sizeof(sigset_t)) | 88 | if (sigsetsize != sizeof(sigset_t)) |
| 89 | return -EINVAL; | 89 | return -EINVAL; |
| 90 | 90 | ||
| 91 | if (copy_from_user(&newset, unewset, sizeof(newset))) | 91 | if (copy_from_user(&newset, unewset, sizeof(newset))) |
| 92 | return -EFAULT; | 92 | return -EFAULT; |
| 93 | sigdelsetmask(&newset, ~_BLOCKABLE); | 93 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 94 | 94 | ||
| 95 | spin_lock_irq(¤t->sighand->siglock); | 95 | spin_lock_irq(¤t->sighand->siglock); |
| 96 | saveset = current->blocked; | 96 | saveset = current->blocked; |
| 97 | current->blocked = newset; | 97 | current->blocked = newset; |
| 98 | recalc_sigpending(); | 98 | recalc_sigpending(); |
| 99 | spin_unlock_irq(¤t->sighand->siglock); | 99 | spin_unlock_irq(¤t->sighand->siglock); |
| 100 | 100 | ||
| 101 | regs->d0 = -EINTR; | 101 | regs->d0 = -EINTR; |
| 102 | while (1) { | 102 | while (1) { |
| 103 | current->state = TASK_INTERRUPTIBLE; | 103 | current->state = TASK_INTERRUPTIBLE; |
| 104 | schedule(); | 104 | schedule(); |
| 105 | if (do_signal(&saveset, regs)) | 105 | if (do_signal(&saveset, regs)) |
| 106 | return -EINTR; | 106 | return -EINTR; |
| 107 | } | 107 | } |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | asmlinkage int | 110 | asmlinkage int |
| 111 | sys_sigaction(int sig, const struct old_sigaction *act, | 111 | sys_sigaction(int sig, const struct old_sigaction *act, |
| 112 | struct old_sigaction *oact) | 112 | struct old_sigaction *oact) |
| 113 | { | 113 | { |
| 114 | struct k_sigaction new_ka, old_ka; | 114 | struct k_sigaction new_ka, old_ka; |
| 115 | int ret; | 115 | int ret; |
| 116 | 116 | ||
| 117 | if (act) { | 117 | if (act) { |
| 118 | old_sigset_t mask; | 118 | old_sigset_t mask; |
| 119 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 119 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
| 120 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 120 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
| 121 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 121 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) |
| 122 | return -EFAULT; | 122 | return -EFAULT; |
| 123 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | 123 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); |
| 124 | __get_user(mask, &act->sa_mask); | 124 | __get_user(mask, &act->sa_mask); |
| 125 | siginitset(&new_ka.sa.sa_mask, mask); | 125 | siginitset(&new_ka.sa.sa_mask, mask); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 128 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
| 129 | 129 | ||
| 130 | if (!ret && oact) { | 130 | if (!ret && oact) { |
| 131 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 131 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
| 132 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 132 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
| 133 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 133 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) |
| 134 | return -EFAULT; | 134 | return -EFAULT; |
| 135 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | 135 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
| 136 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | 136 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | return ret; | 139 | return ret; |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | asmlinkage int | 142 | asmlinkage int |
| 143 | sys_sigaltstack(const stack_t *uss, stack_t *uoss) | 143 | sys_sigaltstack(const stack_t *uss, stack_t *uoss) |
| 144 | { | 144 | { |
| 145 | return do_sigaltstack(uss, uoss, rdusp()); | 145 | return do_sigaltstack(uss, uoss, rdusp()); |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | 148 | ||
| 149 | /* | 149 | /* |
| 150 | * Do a signal return; undo the signal stack. | 150 | * Do a signal return; undo the signal stack. |
| 151 | * | 151 | * |
| 152 | * Keep the return code on the stack quadword aligned! | 152 | * Keep the return code on the stack quadword aligned! |
| 153 | * That makes the cache flush below easier. | 153 | * That makes the cache flush below easier. |
| 154 | */ | 154 | */ |
| 155 | 155 | ||
| 156 | struct sigframe | 156 | struct sigframe |
| 157 | { | 157 | { |
| 158 | char *pretcode; | 158 | char *pretcode; |
| 159 | int sig; | 159 | int sig; |
| 160 | int code; | 160 | int code; |
| 161 | struct sigcontext *psc; | 161 | struct sigcontext *psc; |
| 162 | char retcode[8]; | 162 | char retcode[8]; |
| 163 | unsigned long extramask[_NSIG_WORDS-1]; | 163 | unsigned long extramask[_NSIG_WORDS-1]; |
| 164 | struct sigcontext sc; | 164 | struct sigcontext sc; |
| 165 | }; | 165 | }; |
| 166 | 166 | ||
| 167 | struct rt_sigframe | 167 | struct rt_sigframe |
| 168 | { | 168 | { |
| 169 | char *pretcode; | 169 | char *pretcode; |
| 170 | int sig; | 170 | int sig; |
| 171 | struct siginfo *pinfo; | 171 | struct siginfo *pinfo; |
| 172 | void *puc; | 172 | void *puc; |
| 173 | char retcode[8]; | 173 | char retcode[8]; |
| 174 | struct siginfo info; | 174 | struct siginfo info; |
| 175 | struct ucontext uc; | 175 | struct ucontext uc; |
| 176 | }; | 176 | }; |
| 177 | 177 | ||
| 178 | #ifdef CONFIG_FPU | 178 | #ifdef CONFIG_FPU |
| 179 | 179 | ||
| 180 | static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ | 180 | static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ |
| 181 | 181 | ||
| 182 | static inline int restore_fpu_state(struct sigcontext *sc) | 182 | static inline int restore_fpu_state(struct sigcontext *sc) |
| 183 | { | 183 | { |
| 184 | int err = 1; | 184 | int err = 1; |
| 185 | 185 | ||
| 186 | if (FPU_IS_EMU) { | 186 | if (FPU_IS_EMU) { |
| 187 | /* restore registers */ | 187 | /* restore registers */ |
| 188 | memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); | 188 | memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); |
| 189 | memcpy(current->thread.fp, sc->sc_fpregs, 24); | 189 | memcpy(current->thread.fp, sc->sc_fpregs, 24); |
| 190 | return 0; | 190 | return 0; |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | if (sc->sc_fpstate[0]) { | 193 | if (sc->sc_fpstate[0]) { |
| 194 | /* Verify the frame format. */ | 194 | /* Verify the frame format. */ |
| 195 | if (sc->sc_fpstate[0] != fpu_version) | 195 | if (sc->sc_fpstate[0] != fpu_version) |
| 196 | goto out; | 196 | goto out; |
| 197 | 197 | ||
| 198 | __asm__ volatile (".chip 68k/68881\n\t" | 198 | __asm__ volatile (".chip 68k/68881\n\t" |
| 199 | "fmovemx %0,%/fp0-%/fp1\n\t" | 199 | "fmovemx %0,%/fp0-%/fp1\n\t" |
| 200 | "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" | 200 | "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" |
| 201 | ".chip 68k" | 201 | ".chip 68k" |
| 202 | : /* no outputs */ | 202 | : /* no outputs */ |
| 203 | : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); | 203 | : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); |
| 204 | } | 204 | } |
| 205 | __asm__ volatile (".chip 68k/68881\n\t" | 205 | __asm__ volatile (".chip 68k/68881\n\t" |
| 206 | "frestore %0\n\t" | 206 | "frestore %0\n\t" |
| 207 | ".chip 68k" : : "m" (*sc->sc_fpstate)); | 207 | ".chip 68k" : : "m" (*sc->sc_fpstate)); |
| 208 | err = 0; | 208 | err = 0; |
| 209 | 209 | ||
| 210 | out: | 210 | out: |
| 211 | return err; | 211 | return err; |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | #define FPCONTEXT_SIZE 216 | 214 | #define FPCONTEXT_SIZE 216 |
| 215 | #define uc_fpstate uc_filler[0] | 215 | #define uc_fpstate uc_filler[0] |
| 216 | #define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] | 216 | #define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] |
| 217 | #define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] | 217 | #define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] |
| 218 | 218 | ||
| 219 | static inline int rt_restore_fpu_state(struct ucontext *uc) | 219 | static inline int rt_restore_fpu_state(struct ucontext *uc) |
| 220 | { | 220 | { |
| 221 | unsigned char fpstate[FPCONTEXT_SIZE]; | 221 | unsigned char fpstate[FPCONTEXT_SIZE]; |
| 222 | int context_size = 0; | 222 | int context_size = 0; |
| 223 | fpregset_t fpregs; | 223 | fpregset_t fpregs; |
| 224 | int err = 1; | 224 | int err = 1; |
| 225 | 225 | ||
| 226 | if (FPU_IS_EMU) { | 226 | if (FPU_IS_EMU) { |
| 227 | /* restore fpu control register */ | 227 | /* restore fpu control register */ |
| 228 | if (__copy_from_user(current->thread.fpcntl, | 228 | if (__copy_from_user(current->thread.fpcntl, |
| 229 | &uc->uc_mcontext.fpregs.f_pcr, 12)) | 229 | &uc->uc_mcontext.fpregs.f_pcr, 12)) |
| 230 | goto out; | 230 | goto out; |
| 231 | /* restore all other fpu register */ | 231 | /* restore all other fpu register */ |
| 232 | if (__copy_from_user(current->thread.fp, | 232 | if (__copy_from_user(current->thread.fp, |
| 233 | uc->uc_mcontext.fpregs.f_fpregs, 96)) | 233 | uc->uc_mcontext.fpregs.f_fpregs, 96)) |
| 234 | goto out; | 234 | goto out; |
| 235 | return 0; | 235 | return 0; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) | 238 | if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) |
| 239 | goto out; | 239 | goto out; |
| 240 | if (fpstate[0]) { | 240 | if (fpstate[0]) { |
| 241 | context_size = fpstate[1]; | 241 | context_size = fpstate[1]; |
| 242 | 242 | ||
| 243 | /* Verify the frame format. */ | 243 | /* Verify the frame format. */ |
| 244 | if (fpstate[0] != fpu_version) | 244 | if (fpstate[0] != fpu_version) |
| 245 | goto out; | 245 | goto out; |
| 246 | if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, | 246 | if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, |
| 247 | sizeof(fpregs))) | 247 | sizeof(fpregs))) |
| 248 | goto out; | 248 | goto out; |
| 249 | __asm__ volatile (".chip 68k/68881\n\t" | 249 | __asm__ volatile (".chip 68k/68881\n\t" |
| 250 | "fmovemx %0,%/fp0-%/fp7\n\t" | 250 | "fmovemx %0,%/fp0-%/fp7\n\t" |
| 251 | "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" | 251 | "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" |
| 252 | ".chip 68k" | 252 | ".chip 68k" |
| 253 | : /* no outputs */ | 253 | : /* no outputs */ |
| 254 | : "m" (*fpregs.f_fpregs), | 254 | : "m" (*fpregs.f_fpregs), |
| 255 | "m" (fpregs.f_pcr)); | 255 | "m" (fpregs.f_pcr)); |
| 256 | } | 256 | } |
| 257 | if (context_size && | 257 | if (context_size && |
| 258 | __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1, | 258 | __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1, |
| 259 | context_size)) | 259 | context_size)) |
| 260 | goto out; | 260 | goto out; |
| 261 | __asm__ volatile (".chip 68k/68881\n\t" | 261 | __asm__ volatile (".chip 68k/68881\n\t" |
| 262 | "frestore %0\n\t" | 262 | "frestore %0\n\t" |
| 263 | ".chip 68k" : : "m" (*fpstate)); | 263 | ".chip 68k" : : "m" (*fpstate)); |
| 264 | err = 0; | 264 | err = 0; |
| 265 | 265 | ||
| 266 | out: | 266 | out: |
| 267 | return err; | 267 | return err; |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | #endif | 270 | #endif |
| 271 | 271 | ||
| 272 | static inline int | 272 | static inline int |
| 273 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp, | 273 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp, |
| 274 | int *pd0) | 274 | int *pd0) |
| 275 | { | 275 | { |
| 276 | int formatvec; | 276 | int formatvec; |
| 277 | struct sigcontext context; | 277 | struct sigcontext context; |
| 278 | int err = 0; | 278 | int err = 0; |
| 279 | 279 | ||
| 280 | /* get previous context */ | 280 | /* get previous context */ |
| 281 | if (copy_from_user(&context, usc, sizeof(context))) | 281 | if (copy_from_user(&context, usc, sizeof(context))) |
| 282 | goto badframe; | 282 | goto badframe; |
| 283 | 283 | ||
| 284 | /* restore passed registers */ | 284 | /* restore passed registers */ |
| 285 | regs->d1 = context.sc_d1; | 285 | regs->d1 = context.sc_d1; |
| 286 | regs->a0 = context.sc_a0; | 286 | regs->a0 = context.sc_a0; |
| 287 | regs->a1 = context.sc_a1; | 287 | regs->a1 = context.sc_a1; |
| 288 | ((struct switch_stack *)regs - 1)->a5 = context.sc_a5; | 288 | ((struct switch_stack *)regs - 1)->a5 = context.sc_a5; |
| 289 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); | 289 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); |
| 290 | regs->pc = context.sc_pc; | 290 | regs->pc = context.sc_pc; |
| 291 | regs->orig_d0 = -1; /* disable syscall checks */ | 291 | regs->orig_d0 = -1; /* disable syscall checks */ |
| 292 | wrusp(context.sc_usp); | 292 | wrusp(context.sc_usp); |
| 293 | formatvec = context.sc_formatvec; | 293 | formatvec = context.sc_formatvec; |
| 294 | regs->format = formatvec >> 12; | 294 | regs->format = formatvec >> 12; |
| 295 | regs->vector = formatvec & 0xfff; | 295 | regs->vector = formatvec & 0xfff; |
| 296 | 296 | ||
| 297 | #ifdef CONFIG_FPU | 297 | #ifdef CONFIG_FPU |
| 298 | err = restore_fpu_state(&context); | 298 | err = restore_fpu_state(&context); |
| 299 | #endif | 299 | #endif |
| 300 | 300 | ||
| 301 | *pd0 = context.sc_d0; | 301 | *pd0 = context.sc_d0; |
| 302 | return err; | 302 | return err; |
| 303 | 303 | ||
| 304 | badframe: | 304 | badframe: |
| 305 | return 1; | 305 | return 1; |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | static inline int | 308 | static inline int |
| 309 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, | 309 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, |
| 310 | struct ucontext *uc, int *pd0) | 310 | struct ucontext *uc, int *pd0) |
| 311 | { | 311 | { |
| 312 | int temp; | 312 | int temp; |
| 313 | greg_t *gregs = uc->uc_mcontext.gregs; | 313 | greg_t *gregs = uc->uc_mcontext.gregs; |
| 314 | unsigned long usp; | 314 | unsigned long usp; |
| 315 | int err; | 315 | int err; |
| 316 | 316 | ||
| 317 | err = __get_user(temp, &uc->uc_mcontext.version); | 317 | err = __get_user(temp, &uc->uc_mcontext.version); |
| 318 | if (temp != MCONTEXT_VERSION) | 318 | if (temp != MCONTEXT_VERSION) |
| 319 | goto badframe; | 319 | goto badframe; |
| 320 | /* restore passed registers */ | 320 | /* restore passed registers */ |
| 321 | err |= __get_user(regs->d0, &gregs[0]); | 321 | err |= __get_user(regs->d0, &gregs[0]); |
| 322 | err |= __get_user(regs->d1, &gregs[1]); | 322 | err |= __get_user(regs->d1, &gregs[1]); |
| 323 | err |= __get_user(regs->d2, &gregs[2]); | 323 | err |= __get_user(regs->d2, &gregs[2]); |
| 324 | err |= __get_user(regs->d3, &gregs[3]); | 324 | err |= __get_user(regs->d3, &gregs[3]); |
| 325 | err |= __get_user(regs->d4, &gregs[4]); | 325 | err |= __get_user(regs->d4, &gregs[4]); |
| 326 | err |= __get_user(regs->d5, &gregs[5]); | 326 | err |= __get_user(regs->d5, &gregs[5]); |
| 327 | err |= __get_user(sw->d6, &gregs[6]); | 327 | err |= __get_user(sw->d6, &gregs[6]); |
| 328 | err |= __get_user(sw->d7, &gregs[7]); | 328 | err |= __get_user(sw->d7, &gregs[7]); |
| 329 | err |= __get_user(regs->a0, &gregs[8]); | 329 | err |= __get_user(regs->a0, &gregs[8]); |
| 330 | err |= __get_user(regs->a1, &gregs[9]); | 330 | err |= __get_user(regs->a1, &gregs[9]); |
| 331 | err |= __get_user(regs->a2, &gregs[10]); | 331 | err |= __get_user(regs->a2, &gregs[10]); |
| 332 | err |= __get_user(sw->a3, &gregs[11]); | 332 | err |= __get_user(sw->a3, &gregs[11]); |
| 333 | err |= __get_user(sw->a4, &gregs[12]); | 333 | err |= __get_user(sw->a4, &gregs[12]); |
| 334 | err |= __get_user(sw->a5, &gregs[13]); | 334 | err |= __get_user(sw->a5, &gregs[13]); |
| 335 | err |= __get_user(sw->a6, &gregs[14]); | 335 | err |= __get_user(sw->a6, &gregs[14]); |
| 336 | err |= __get_user(usp, &gregs[15]); | 336 | err |= __get_user(usp, &gregs[15]); |
| 337 | wrusp(usp); | 337 | wrusp(usp); |
| 338 | err |= __get_user(regs->pc, &gregs[16]); | 338 | err |= __get_user(regs->pc, &gregs[16]); |
| 339 | err |= __get_user(temp, &gregs[17]); | 339 | err |= __get_user(temp, &gregs[17]); |
| 340 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); | 340 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); |
| 341 | regs->orig_d0 = -1; /* disable syscall checks */ | 341 | regs->orig_d0 = -1; /* disable syscall checks */ |
| 342 | regs->format = temp >> 12; | 342 | regs->format = temp >> 12; |
| 343 | regs->vector = temp & 0xfff; | 343 | regs->vector = temp & 0xfff; |
| 344 | 344 | ||
| 345 | if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) | 345 | if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) |
| 346 | goto badframe; | 346 | goto badframe; |
| 347 | 347 | ||
| 348 | *pd0 = regs->d0; | 348 | *pd0 = regs->d0; |
| 349 | return err; | 349 | return err; |
| 350 | 350 | ||
| 351 | badframe: | 351 | badframe: |
| 352 | return 1; | 352 | return 1; |
| 353 | } | 353 | } |
| 354 | 354 | ||
| 355 | asmlinkage int do_sigreturn(unsigned long __unused) | 355 | asmlinkage int do_sigreturn(unsigned long __unused) |
| 356 | { | 356 | { |
| 357 | struct switch_stack *sw = (struct switch_stack *) &__unused; | 357 | struct switch_stack *sw = (struct switch_stack *) &__unused; |
| 358 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | 358 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); |
| 359 | unsigned long usp = rdusp(); | 359 | unsigned long usp = rdusp(); |
| 360 | struct sigframe *frame = (struct sigframe *)(usp - 4); | 360 | struct sigframe *frame = (struct sigframe *)(usp - 4); |
| 361 | sigset_t set; | 361 | sigset_t set; |
| 362 | int d0; | 362 | int d0; |
| 363 | 363 | ||
| 364 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 364 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 365 | goto badframe; | 365 | goto badframe; |
| 366 | if (__get_user(set.sig[0], &frame->sc.sc_mask) || | 366 | if (__get_user(set.sig[0], &frame->sc.sc_mask) || |
| 367 | (_NSIG_WORDS > 1 && | 367 | (_NSIG_WORDS > 1 && |
| 368 | __copy_from_user(&set.sig[1], &frame->extramask, | 368 | __copy_from_user(&set.sig[1], &frame->extramask, |
| 369 | sizeof(frame->extramask)))) | 369 | sizeof(frame->extramask)))) |
| 370 | goto badframe; | 370 | goto badframe; |
| 371 | 371 | ||
| 372 | sigdelsetmask(&set, ~_BLOCKABLE); | 372 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 373 | spin_lock_irq(¤t->sighand->siglock); | 373 | spin_lock_irq(¤t->sighand->siglock); |
| 374 | current->blocked = set; | 374 | current->blocked = set; |
| 375 | recalc_sigpending(); | 375 | recalc_sigpending(); |
| 376 | spin_unlock_irq(¤t->sighand->siglock); | 376 | spin_unlock_irq(¤t->sighand->siglock); |
| 377 | 377 | ||
| 378 | if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) | 378 | if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) |
| 379 | goto badframe; | 379 | goto badframe; |
| 380 | return d0; | 380 | return d0; |
| 381 | 381 | ||
| 382 | badframe: | 382 | badframe: |
| 383 | force_sig(SIGSEGV, current); | 383 | force_sig(SIGSEGV, current); |
| 384 | return 0; | 384 | return 0; |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | asmlinkage int do_rt_sigreturn(unsigned long __unused) | 387 | asmlinkage int do_rt_sigreturn(unsigned long __unused) |
| 388 | { | 388 | { |
| 389 | struct switch_stack *sw = (struct switch_stack *) &__unused; | 389 | struct switch_stack *sw = (struct switch_stack *) &__unused; |
| 390 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | 390 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); |
| 391 | unsigned long usp = rdusp(); | 391 | unsigned long usp = rdusp(); |
| 392 | struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); | 392 | struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); |
| 393 | sigset_t set; | 393 | sigset_t set; |
| 394 | int d0; | 394 | int d0; |
| 395 | 395 | ||
| 396 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 396 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 397 | goto badframe; | 397 | goto badframe; |
| 398 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 398 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| 399 | goto badframe; | 399 | goto badframe; |
| 400 | 400 | ||
| 401 | sigdelsetmask(&set, ~_BLOCKABLE); | 401 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 402 | spin_lock_irq(¤t->sighand->siglock); | 402 | spin_lock_irq(¤t->sighand->siglock); |
| 403 | current->blocked = set; | 403 | current->blocked = set; |
| 404 | recalc_sigpending(); | 404 | recalc_sigpending(); |
| 405 | spin_unlock_irq(¤t->sighand->siglock); | 405 | spin_unlock_irq(¤t->sighand->siglock); |
| 406 | 406 | ||
| 407 | if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) | 407 | if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) |
| 408 | goto badframe; | 408 | goto badframe; |
| 409 | return d0; | 409 | return d0; |
| 410 | 410 | ||
| 411 | badframe: | 411 | badframe: |
| 412 | force_sig(SIGSEGV, current); | 412 | force_sig(SIGSEGV, current); |
| 413 | return 0; | 413 | return 0; |
| 414 | } | 414 | } |
| 415 | 415 | ||
| 416 | #ifdef CONFIG_FPU | 416 | #ifdef CONFIG_FPU |
| 417 | /* | 417 | /* |
| 418 | * Set up a signal frame. | 418 | * Set up a signal frame. |
| 419 | */ | 419 | */ |
| 420 | 420 | ||
| 421 | static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) | 421 | static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) |
| 422 | { | 422 | { |
| 423 | if (FPU_IS_EMU) { | 423 | if (FPU_IS_EMU) { |
| 424 | /* save registers */ | 424 | /* save registers */ |
| 425 | memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); | 425 | memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); |
| 426 | memcpy(sc->sc_fpregs, current->thread.fp, 24); | 426 | memcpy(sc->sc_fpregs, current->thread.fp, 24); |
| 427 | return; | 427 | return; |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | __asm__ volatile (".chip 68k/68881\n\t" | 430 | __asm__ volatile (".chip 68k/68881\n\t" |
| 431 | "fsave %0\n\t" | 431 | "fsave %0\n\t" |
| 432 | ".chip 68k" | 432 | ".chip 68k" |
| 433 | : : "m" (*sc->sc_fpstate) : "memory"); | 433 | : : "m" (*sc->sc_fpstate) : "memory"); |
| 434 | 434 | ||
| 435 | if (sc->sc_fpstate[0]) { | 435 | if (sc->sc_fpstate[0]) { |
| 436 | fpu_version = sc->sc_fpstate[0]; | 436 | fpu_version = sc->sc_fpstate[0]; |
| 437 | __asm__ volatile (".chip 68k/68881\n\t" | 437 | __asm__ volatile (".chip 68k/68881\n\t" |
| 438 | "fmovemx %/fp0-%/fp1,%0\n\t" | 438 | "fmovemx %/fp0-%/fp1,%0\n\t" |
| 439 | "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" | 439 | "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" |
| 440 | ".chip 68k" | 440 | ".chip 68k" |
| 441 | : /* no outputs */ | 441 | : /* no outputs */ |
| 442 | : "m" (*sc->sc_fpregs), | 442 | : "m" (*sc->sc_fpregs), |
| 443 | "m" (*sc->sc_fpcntl) | 443 | "m" (*sc->sc_fpcntl) |
| 444 | : "memory"); | 444 | : "memory"); |
| 445 | } | 445 | } |
| 446 | } | 446 | } |
| 447 | 447 | ||
| 448 | static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) | 448 | static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) |
| 449 | { | 449 | { |
| 450 | unsigned char fpstate[FPCONTEXT_SIZE]; | 450 | unsigned char fpstate[FPCONTEXT_SIZE]; |
| 451 | int context_size = 0; | 451 | int context_size = 0; |
| 452 | int err = 0; | 452 | int err = 0; |
| 453 | 453 | ||
| 454 | if (FPU_IS_EMU) { | 454 | if (FPU_IS_EMU) { |
| 455 | /* save fpu control register */ | 455 | /* save fpu control register */ |
| 456 | err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr, | 456 | err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr, |
| 457 | current->thread.fpcntl, 12); | 457 | current->thread.fpcntl, 12); |
| 458 | /* save all other fpu register */ | 458 | /* save all other fpu register */ |
| 459 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, | 459 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, |
| 460 | current->thread.fp, 96); | 460 | current->thread.fp, 96); |
| 461 | return err; | 461 | return err; |
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | __asm__ volatile (".chip 68k/68881\n\t" | 464 | __asm__ volatile (".chip 68k/68881\n\t" |
| 465 | "fsave %0\n\t" | 465 | "fsave %0\n\t" |
| 466 | ".chip 68k" | 466 | ".chip 68k" |
| 467 | : : "m" (*fpstate) : "memory"); | 467 | : : "m" (*fpstate) : "memory"); |
| 468 | 468 | ||
| 469 | err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate); | 469 | err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate); |
| 470 | if (fpstate[0]) { | 470 | if (fpstate[0]) { |
| 471 | fpregset_t fpregs; | 471 | fpregset_t fpregs; |
| 472 | context_size = fpstate[1]; | 472 | context_size = fpstate[1]; |
| 473 | fpu_version = fpstate[0]; | 473 | fpu_version = fpstate[0]; |
| 474 | __asm__ volatile (".chip 68k/68881\n\t" | 474 | __asm__ volatile (".chip 68k/68881\n\t" |
| 475 | "fmovemx %/fp0-%/fp7,%0\n\t" | 475 | "fmovemx %/fp0-%/fp7,%0\n\t" |
| 476 | "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" | 476 | "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" |
| 477 | ".chip 68k" | 477 | ".chip 68k" |
| 478 | : /* no outputs */ | 478 | : /* no outputs */ |
| 479 | : "m" (*fpregs.f_fpregs), | 479 | : "m" (*fpregs.f_fpregs), |
| 480 | "m" (fpregs.f_pcr) | 480 | "m" (fpregs.f_pcr) |
| 481 | : "memory"); | 481 | : "memory"); |
| 482 | err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, | 482 | err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, |
| 483 | sizeof(fpregs)); | 483 | sizeof(fpregs)); |
| 484 | } | 484 | } |
| 485 | if (context_size) | 485 | if (context_size) |
| 486 | err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4, | 486 | err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4, |
| 487 | context_size); | 487 | context_size); |
| 488 | return err; | 488 | return err; |
| 489 | } | 489 | } |
| 490 | 490 | ||
| 491 | #endif | 491 | #endif |
| 492 | 492 | ||
| 493 | static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, | 493 | static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, |
| 494 | unsigned long mask) | 494 | unsigned long mask) |
| 495 | { | 495 | { |
| 496 | sc->sc_mask = mask; | 496 | sc->sc_mask = mask; |
| 497 | sc->sc_usp = rdusp(); | 497 | sc->sc_usp = rdusp(); |
| 498 | sc->sc_d0 = regs->d0; | 498 | sc->sc_d0 = regs->d0; |
| 499 | sc->sc_d1 = regs->d1; | 499 | sc->sc_d1 = regs->d1; |
| 500 | sc->sc_a0 = regs->a0; | 500 | sc->sc_a0 = regs->a0; |
| 501 | sc->sc_a1 = regs->a1; | 501 | sc->sc_a1 = regs->a1; |
| 502 | sc->sc_a5 = ((struct switch_stack *)regs - 1)->a5; | 502 | sc->sc_a5 = ((struct switch_stack *)regs - 1)->a5; |
| 503 | sc->sc_sr = regs->sr; | 503 | sc->sc_sr = regs->sr; |
| 504 | sc->sc_pc = regs->pc; | 504 | sc->sc_pc = regs->pc; |
| 505 | sc->sc_formatvec = regs->format << 12 | regs->vector; | 505 | sc->sc_formatvec = regs->format << 12 | regs->vector; |
| 506 | #ifdef CONFIG_FPU | 506 | #ifdef CONFIG_FPU |
| 507 | save_fpu_state(sc, regs); | 507 | save_fpu_state(sc, regs); |
| 508 | #endif | 508 | #endif |
| 509 | } | 509 | } |
| 510 | 510 | ||
| 511 | static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) | 511 | static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) |
| 512 | { | 512 | { |
| 513 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | 513 | struct switch_stack *sw = (struct switch_stack *)regs - 1; |
| 514 | greg_t *gregs = uc->uc_mcontext.gregs; | 514 | greg_t *gregs = uc->uc_mcontext.gregs; |
| 515 | int err = 0; | 515 | int err = 0; |
| 516 | 516 | ||
| 517 | err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); | 517 | err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); |
| 518 | err |= __put_user(regs->d0, &gregs[0]); | 518 | err |= __put_user(regs->d0, &gregs[0]); |
| 519 | err |= __put_user(regs->d1, &gregs[1]); | 519 | err |= __put_user(regs->d1, &gregs[1]); |
| 520 | err |= __put_user(regs->d2, &gregs[2]); | 520 | err |= __put_user(regs->d2, &gregs[2]); |
| 521 | err |= __put_user(regs->d3, &gregs[3]); | 521 | err |= __put_user(regs->d3, &gregs[3]); |
| 522 | err |= __put_user(regs->d4, &gregs[4]); | 522 | err |= __put_user(regs->d4, &gregs[4]); |
| 523 | err |= __put_user(regs->d5, &gregs[5]); | 523 | err |= __put_user(regs->d5, &gregs[5]); |
| 524 | err |= __put_user(sw->d6, &gregs[6]); | 524 | err |= __put_user(sw->d6, &gregs[6]); |
| 525 | err |= __put_user(sw->d7, &gregs[7]); | 525 | err |= __put_user(sw->d7, &gregs[7]); |
| 526 | err |= __put_user(regs->a0, &gregs[8]); | 526 | err |= __put_user(regs->a0, &gregs[8]); |
| 527 | err |= __put_user(regs->a1, &gregs[9]); | 527 | err |= __put_user(regs->a1, &gregs[9]); |
| 528 | err |= __put_user(regs->a2, &gregs[10]); | 528 | err |= __put_user(regs->a2, &gregs[10]); |
| 529 | err |= __put_user(sw->a3, &gregs[11]); | 529 | err |= __put_user(sw->a3, &gregs[11]); |
| 530 | err |= __put_user(sw->a4, &gregs[12]); | 530 | err |= __put_user(sw->a4, &gregs[12]); |
| 531 | err |= __put_user(sw->a5, &gregs[13]); | 531 | err |= __put_user(sw->a5, &gregs[13]); |
| 532 | err |= __put_user(sw->a6, &gregs[14]); | 532 | err |= __put_user(sw->a6, &gregs[14]); |
| 533 | err |= __put_user(rdusp(), &gregs[15]); | 533 | err |= __put_user(rdusp(), &gregs[15]); |
| 534 | err |= __put_user(regs->pc, &gregs[16]); | 534 | err |= __put_user(regs->pc, &gregs[16]); |
| 535 | err |= __put_user(regs->sr, &gregs[17]); | 535 | err |= __put_user(regs->sr, &gregs[17]); |
| 536 | #ifdef CONFIG_FPU | 536 | #ifdef CONFIG_FPU |
| 537 | err |= rt_save_fpu_state(uc, regs); | 537 | err |= rt_save_fpu_state(uc, regs); |
| 538 | #endif | 538 | #endif |
| 539 | return err; | 539 | return err; |
| 540 | } | 540 | } |
| 541 | 541 | ||
| 542 | static inline void push_cache (unsigned long vaddr) | 542 | static inline void push_cache (unsigned long vaddr) |
| 543 | { | 543 | { |
| 544 | } | 544 | } |
| 545 | 545 | ||
| 546 | static inline void * | 546 | static inline void * |
| 547 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 547 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) |
| 548 | { | 548 | { |
| 549 | unsigned long usp; | 549 | unsigned long usp; |
| 550 | 550 | ||
| 551 | /* Default to using normal stack. */ | 551 | /* Default to using normal stack. */ |
| 552 | usp = rdusp(); | 552 | usp = rdusp(); |
| 553 | 553 | ||
| 554 | /* This is the X/Open sanctioned signal stack switching. */ | 554 | /* This is the X/Open sanctioned signal stack switching. */ |
| 555 | if (ka->sa.sa_flags & SA_ONSTACK) { | 555 | if (ka->sa.sa_flags & SA_ONSTACK) { |
| 556 | if (!on_sig_stack(usp)) | 556 | if (!sas_ss_flags(usp)) |
| 557 | usp = current->sas_ss_sp + current->sas_ss_size; | 557 | usp = current->sas_ss_sp + current->sas_ss_size; |
| 558 | } | 558 | } |
| 559 | return (void *)((usp - frame_size) & -8UL); | 559 | return (void *)((usp - frame_size) & -8UL); |
| 560 | } | 560 | } |
| 561 | 561 | ||
| 562 | static void setup_frame (int sig, struct k_sigaction *ka, | 562 | static void setup_frame (int sig, struct k_sigaction *ka, |
| 563 | sigset_t *set, struct pt_regs *regs) | 563 | sigset_t *set, struct pt_regs *regs) |
| 564 | { | 564 | { |
| 565 | struct sigframe *frame; | 565 | struct sigframe *frame; |
| 566 | struct sigcontext context; | 566 | struct sigcontext context; |
| 567 | int err = 0; | 567 | int err = 0; |
| 568 | 568 | ||
| 569 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 569 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
| 570 | 570 | ||
| 571 | err |= __put_user((current_thread_info()->exec_domain | 571 | err |= __put_user((current_thread_info()->exec_domain |
| 572 | && current_thread_info()->exec_domain->signal_invmap | 572 | && current_thread_info()->exec_domain->signal_invmap |
| 573 | && sig < 32 | 573 | && sig < 32 |
| 574 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 574 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 575 | : sig), | 575 | : sig), |
| 576 | &frame->sig); | 576 | &frame->sig); |
| 577 | 577 | ||
| 578 | err |= __put_user(regs->vector, &frame->code); | 578 | err |= __put_user(regs->vector, &frame->code); |
| 579 | err |= __put_user(&frame->sc, &frame->psc); | 579 | err |= __put_user(&frame->sc, &frame->psc); |
| 580 | 580 | ||
| 581 | if (_NSIG_WORDS > 1) | 581 | if (_NSIG_WORDS > 1) |
| 582 | err |= copy_to_user(frame->extramask, &set->sig[1], | 582 | err |= copy_to_user(frame->extramask, &set->sig[1], |
| 583 | sizeof(frame->extramask)); | 583 | sizeof(frame->extramask)); |
| 584 | 584 | ||
| 585 | setup_sigcontext(&context, regs, set->sig[0]); | 585 | setup_sigcontext(&context, regs, set->sig[0]); |
| 586 | err |= copy_to_user (&frame->sc, &context, sizeof(context)); | 586 | err |= copy_to_user (&frame->sc, &context, sizeof(context)); |
| 587 | 587 | ||
| 588 | /* Set up to return from userspace. */ | 588 | /* Set up to return from userspace. */ |
| 589 | err |= __put_user(frame->retcode, &frame->pretcode); | 589 | err |= __put_user(frame->retcode, &frame->pretcode); |
| 590 | /* moveq #,d0; trap #0 */ | 590 | /* moveq #,d0; trap #0 */ |
| 591 | err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), | 591 | err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), |
| 592 | (long *)(frame->retcode)); | 592 | (long *)(frame->retcode)); |
| 593 | 593 | ||
| 594 | if (err) | 594 | if (err) |
| 595 | goto give_sigsegv; | 595 | goto give_sigsegv; |
| 596 | 596 | ||
| 597 | push_cache ((unsigned long) &frame->retcode); | 597 | push_cache ((unsigned long) &frame->retcode); |
| 598 | 598 | ||
| 599 | /* Set up registers for signal handler */ | 599 | /* Set up registers for signal handler */ |
| 600 | wrusp ((unsigned long) frame); | 600 | wrusp ((unsigned long) frame); |
| 601 | regs->pc = (unsigned long) ka->sa.sa_handler; | 601 | regs->pc = (unsigned long) ka->sa.sa_handler; |
| 602 | ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data; | 602 | ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data; |
| 603 | regs->format = 0x4; /*set format byte to make stack appear modulo 4 | 603 | regs->format = 0x4; /*set format byte to make stack appear modulo 4 |
| 604 | which it will be when doing the rte */ | 604 | which it will be when doing the rte */ |
| 605 | 605 | ||
| 606 | adjust_stack: | 606 | adjust_stack: |
| 607 | /* Prepare to skip over the extra stuff in the exception frame. */ | 607 | /* Prepare to skip over the extra stuff in the exception frame. */ |
| 608 | if (regs->stkadj) { | 608 | if (regs->stkadj) { |
| 609 | struct pt_regs *tregs = | 609 | struct pt_regs *tregs = |
| 610 | (struct pt_regs *)((ulong)regs + regs->stkadj); | 610 | (struct pt_regs *)((ulong)regs + regs->stkadj); |
| 611 | #if DEBUG | 611 | #if DEBUG |
| 612 | printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj); | 612 | printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj); |
| 613 | #endif | 613 | #endif |
| 614 | /* This must be copied with decreasing addresses to | 614 | /* This must be copied with decreasing addresses to |
| 615 | handle overlaps. */ | 615 | handle overlaps. */ |
| 616 | tregs->vector = 0; | 616 | tregs->vector = 0; |
| 617 | tregs->format = 0; | 617 | tregs->format = 0; |
| 618 | tregs->pc = regs->pc; | 618 | tregs->pc = regs->pc; |
| 619 | tregs->sr = regs->sr; | 619 | tregs->sr = regs->sr; |
| 620 | } | 620 | } |
| 621 | return; | 621 | return; |
| 622 | 622 | ||
| 623 | give_sigsegv: | 623 | give_sigsegv: |
| 624 | force_sigsegv(sig, current); | 624 | force_sigsegv(sig, current); |
| 625 | goto adjust_stack; | 625 | goto adjust_stack; |
| 626 | } | 626 | } |
| 627 | 627 | ||
| 628 | static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | 628 | static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, |
| 629 | sigset_t *set, struct pt_regs *regs) | 629 | sigset_t *set, struct pt_regs *regs) |
| 630 | { | 630 | { |
| 631 | struct rt_sigframe *frame; | 631 | struct rt_sigframe *frame; |
| 632 | int err = 0; | 632 | int err = 0; |
| 633 | 633 | ||
| 634 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 634 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
| 635 | 635 | ||
| 636 | err |= __put_user((current_thread_info()->exec_domain | 636 | err |= __put_user((current_thread_info()->exec_domain |
| 637 | && current_thread_info()->exec_domain->signal_invmap | 637 | && current_thread_info()->exec_domain->signal_invmap |
| 638 | && sig < 32 | 638 | && sig < 32 |
| 639 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 639 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 640 | : sig), | 640 | : sig), |
| 641 | &frame->sig); | 641 | &frame->sig); |
| 642 | err |= __put_user(&frame->info, &frame->pinfo); | 642 | err |= __put_user(&frame->info, &frame->pinfo); |
| 643 | err |= __put_user(&frame->uc, &frame->puc); | 643 | err |= __put_user(&frame->uc, &frame->puc); |
| 644 | err |= copy_siginfo_to_user(&frame->info, info); | 644 | err |= copy_siginfo_to_user(&frame->info, info); |
| 645 | 645 | ||
| 646 | /* Create the ucontext. */ | 646 | /* Create the ucontext. */ |
| 647 | err |= __put_user(0, &frame->uc.uc_flags); | 647 | err |= __put_user(0, &frame->uc.uc_flags); |
| 648 | err |= __put_user(0, &frame->uc.uc_link); | 648 | err |= __put_user(0, &frame->uc.uc_link); |
| 649 | err |= __put_user((void *)current->sas_ss_sp, | 649 | err |= __put_user((void *)current->sas_ss_sp, |
| 650 | &frame->uc.uc_stack.ss_sp); | 650 | &frame->uc.uc_stack.ss_sp); |
| 651 | err |= __put_user(sas_ss_flags(rdusp()), | 651 | err |= __put_user(sas_ss_flags(rdusp()), |
| 652 | &frame->uc.uc_stack.ss_flags); | 652 | &frame->uc.uc_stack.ss_flags); |
| 653 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 653 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
| 654 | err |= rt_setup_ucontext(&frame->uc, regs); | 654 | err |= rt_setup_ucontext(&frame->uc, regs); |
| 655 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); | 655 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 656 | 656 | ||
| 657 | /* Set up to return from userspace. */ | 657 | /* Set up to return from userspace. */ |
| 658 | err |= __put_user(frame->retcode, &frame->pretcode); | 658 | err |= __put_user(frame->retcode, &frame->pretcode); |
| 659 | /* moveq #,d0; notb d0; trap #0 */ | 659 | /* moveq #,d0; notb d0; trap #0 */ |
| 660 | err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), | 660 | err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), |
| 661 | (long *)(frame->retcode + 0)); | 661 | (long *)(frame->retcode + 0)); |
| 662 | err |= __put_user(0x4e40, (short *)(frame->retcode + 4)); | 662 | err |= __put_user(0x4e40, (short *)(frame->retcode + 4)); |
| 663 | 663 | ||
| 664 | if (err) | 664 | if (err) |
| 665 | goto give_sigsegv; | 665 | goto give_sigsegv; |
| 666 | 666 | ||
| 667 | push_cache ((unsigned long) &frame->retcode); | 667 | push_cache ((unsigned long) &frame->retcode); |
| 668 | 668 | ||
| 669 | /* Set up registers for signal handler */ | 669 | /* Set up registers for signal handler */ |
| 670 | wrusp ((unsigned long) frame); | 670 | wrusp ((unsigned long) frame); |
| 671 | regs->pc = (unsigned long) ka->sa.sa_handler; | 671 | regs->pc = (unsigned long) ka->sa.sa_handler; |
| 672 | ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data; | 672 | ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data; |
| 673 | regs->format = 0x4; /*set format byte to make stack appear modulo 4 | 673 | regs->format = 0x4; /*set format byte to make stack appear modulo 4 |
| 674 | which it will be when doing the rte */ | 674 | which it will be when doing the rte */ |
| 675 | 675 | ||
| 676 | adjust_stack: | 676 | adjust_stack: |
| 677 | /* Prepare to skip over the extra stuff in the exception frame. */ | 677 | /* Prepare to skip over the extra stuff in the exception frame. */ |
| 678 | if (regs->stkadj) { | 678 | if (regs->stkadj) { |
| 679 | struct pt_regs *tregs = | 679 | struct pt_regs *tregs = |
| 680 | (struct pt_regs *)((ulong)regs + regs->stkadj); | 680 | (struct pt_regs *)((ulong)regs + regs->stkadj); |
| 681 | #if DEBUG | 681 | #if DEBUG |
| 682 | printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj); | 682 | printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj); |
| 683 | #endif | 683 | #endif |
| 684 | /* This must be copied with decreasing addresses to | 684 | /* This must be copied with decreasing addresses to |
| 685 | handle overlaps. */ | 685 | handle overlaps. */ |
| 686 | tregs->vector = 0; | 686 | tregs->vector = 0; |
| 687 | tregs->format = 0; | 687 | tregs->format = 0; |
| 688 | tregs->pc = regs->pc; | 688 | tregs->pc = regs->pc; |
| 689 | tregs->sr = regs->sr; | 689 | tregs->sr = regs->sr; |
| 690 | } | 690 | } |
| 691 | return; | 691 | return; |
| 692 | 692 | ||
| 693 | give_sigsegv: | 693 | give_sigsegv: |
| 694 | force_sigsegv(sig, current); | 694 | force_sigsegv(sig, current); |
| 695 | goto adjust_stack; | 695 | goto adjust_stack; |
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | static inline void | 698 | static inline void |
| 699 | handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) | 699 | handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) |
| 700 | { | 700 | { |
| 701 | switch (regs->d0) { | 701 | switch (regs->d0) { |
| 702 | case -ERESTARTNOHAND: | 702 | case -ERESTARTNOHAND: |
| 703 | if (!has_handler) | 703 | if (!has_handler) |
| 704 | goto do_restart; | 704 | goto do_restart; |
| 705 | regs->d0 = -EINTR; | 705 | regs->d0 = -EINTR; |
| 706 | break; | 706 | break; |
| 707 | 707 | ||
| 708 | case -ERESTARTSYS: | 708 | case -ERESTARTSYS: |
| 709 | if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { | 709 | if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { |
| 710 | regs->d0 = -EINTR; | 710 | regs->d0 = -EINTR; |
| 711 | break; | 711 | break; |
| 712 | } | 712 | } |
| 713 | /* fallthrough */ | 713 | /* fallthrough */ |
| 714 | case -ERESTARTNOINTR: | 714 | case -ERESTARTNOINTR: |
| 715 | do_restart: | 715 | do_restart: |
| 716 | regs->d0 = regs->orig_d0; | 716 | regs->d0 = regs->orig_d0; |
| 717 | regs->pc -= 2; | 717 | regs->pc -= 2; |
| 718 | break; | 718 | break; |
| 719 | } | 719 | } |
| 720 | } | 720 | } |
| 721 | 721 | ||
| 722 | /* | 722 | /* |
| 723 | * OK, we're invoking a handler | 723 | * OK, we're invoking a handler |
| 724 | */ | 724 | */ |
| 725 | static void | 725 | static void |
| 726 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | 726 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 727 | sigset_t *oldset, struct pt_regs *regs) | 727 | sigset_t *oldset, struct pt_regs *regs) |
| 728 | { | 728 | { |
| 729 | /* are we from a system call? */ | 729 | /* are we from a system call? */ |
| 730 | if (regs->orig_d0 >= 0) | 730 | if (regs->orig_d0 >= 0) |
| 731 | /* If so, check system call restarting.. */ | 731 | /* If so, check system call restarting.. */ |
| 732 | handle_restart(regs, ka, 1); | 732 | handle_restart(regs, ka, 1); |
| 733 | 733 | ||
| 734 | /* set up the stack frame */ | 734 | /* set up the stack frame */ |
| 735 | if (ka->sa.sa_flags & SA_SIGINFO) | 735 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 736 | setup_rt_frame(sig, ka, info, oldset, regs); | 736 | setup_rt_frame(sig, ka, info, oldset, regs); |
| 737 | else | 737 | else |
| 738 | setup_frame(sig, ka, oldset, regs); | 738 | setup_frame(sig, ka, oldset, regs); |
| 739 | 739 | ||
| 740 | if (ka->sa.sa_flags & SA_ONESHOT) | 740 | if (ka->sa.sa_flags & SA_ONESHOT) |
| 741 | ka->sa.sa_handler = SIG_DFL; | 741 | ka->sa.sa_handler = SIG_DFL; |
| 742 | 742 | ||
| 743 | spin_lock_irq(¤t->sighand->siglock); | 743 | spin_lock_irq(¤t->sighand->siglock); |
| 744 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 744 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
| 745 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 745 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 746 | sigaddset(¤t->blocked,sig); | 746 | sigaddset(¤t->blocked,sig); |
| 747 | recalc_sigpending(); | 747 | recalc_sigpending(); |
| 748 | spin_unlock_irq(¤t->sighand->siglock); | 748 | spin_unlock_irq(¤t->sighand->siglock); |
| 749 | } | 749 | } |
| 750 | 750 | ||
| 751 | /* | 751 | /* |
| 752 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 752 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 753 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 753 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 754 | * mistake. | 754 | * mistake. |
| 755 | */ | 755 | */ |
| 756 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) | 756 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) |
| 757 | { | 757 | { |
| 758 | struct k_sigaction ka; | 758 | struct k_sigaction ka; |
| 759 | siginfo_t info; | 759 | siginfo_t info; |
| 760 | int signr; | 760 | int signr; |
| 761 | 761 | ||
| 762 | /* | 762 | /* |
| 763 | * We want the common case to go fast, which | 763 | * We want the common case to go fast, which |
| 764 | * is why we may in certain cases get here from | 764 | * is why we may in certain cases get here from |
| 765 | * kernel mode. Just return without doing anything | 765 | * kernel mode. Just return without doing anything |
| 766 | * if so. | 766 | * if so. |
| 767 | */ | 767 | */ |
| 768 | if (!user_mode(regs)) | 768 | if (!user_mode(regs)) |
| 769 | return 1; | 769 | return 1; |
| 770 | 770 | ||
| 771 | if (!oldset) | 771 | if (!oldset) |
| 772 | oldset = ¤t->blocked; | 772 | oldset = ¤t->blocked; |
| 773 | 773 | ||
| 774 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 774 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 775 | if (signr > 0) { | 775 | if (signr > 0) { |
| 776 | /* Whee! Actually deliver the signal. */ | 776 | /* Whee! Actually deliver the signal. */ |
| 777 | handle_signal(signr, &ka, &info, oldset, regs); | 777 | handle_signal(signr, &ka, &info, oldset, regs); |
| 778 | return 1; | 778 | return 1; |
| 779 | } | 779 | } |
| 780 | 780 | ||
| 781 | /* Did we come from a system call? */ | 781 | /* Did we come from a system call? */ |
| 782 | if (regs->orig_d0 >= 0) { | 782 | if (regs->orig_d0 >= 0) { |
| 783 | /* Restart the system call - no handlers present */ | 783 | /* Restart the system call - no handlers present */ |
| 784 | if (regs->d0 == -ERESTARTNOHAND | 784 | if (regs->d0 == -ERESTARTNOHAND |
| 785 | || regs->d0 == -ERESTARTSYS | 785 | || regs->d0 == -ERESTARTSYS |
| 786 | || regs->d0 == -ERESTARTNOINTR) { | 786 | || regs->d0 == -ERESTARTNOINTR) { |
| 787 | regs->d0 = regs->orig_d0; | 787 | regs->d0 = regs->orig_d0; |
| 788 | regs->pc -= 2; | 788 | regs->pc -= 2; |
| 789 | } else if (regs->d0 == -ERESTART_RESTARTBLOCK) { | 789 | } else if (regs->d0 == -ERESTART_RESTARTBLOCK) { |
| 790 | regs->d0 = __NR_restart_syscall; | 790 | regs->d0 = __NR_restart_syscall; |
| 791 | regs->pc -= 2; | 791 | regs->pc -= 2; |
| 792 | } | 792 | } |
| 793 | } | 793 | } |
| 794 | return 0; | 794 | return 0; |
| 795 | } | 795 | } |
| 796 | 796 |
arch/parisc/kernel/signal.c
| 1 | /* | 1 | /* |
| 2 | * linux/arch/parisc/kernel/signal.c: Architecture-specific signal | 2 | * linux/arch/parisc/kernel/signal.c: Architecture-specific signal |
| 3 | * handling support. | 3 | * handling support. |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org> | 5 | * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org> |
| 6 | * Copyright (C) 2000 Linuxcare, Inc. | 6 | * Copyright (C) 2000 Linuxcare, Inc. |
| 7 | * | 7 | * |
| 8 | * Based on the ia64, i386, and alpha versions. | 8 | * Based on the ia64, i386, and alpha versions. |
| 9 | * | 9 | * |
| 10 | * Like the IA-64, we are a recent enough port (we are *starting* | 10 | * Like the IA-64, we are a recent enough port (we are *starting* |
| 11 | * with glibc2.2) that we do not need to support the old non-realtime | 11 | * with glibc2.2) that we do not need to support the old non-realtime |
| 12 | * Linux signals. Therefore we don't. HP/UX signals will go in | 12 | * Linux signals. Therefore we don't. HP/UX signals will go in |
| 13 | * arch/parisc/hpux/signal.c when we figure out how to do them. | 13 | * arch/parisc/hpux/signal.c when we figure out how to do them. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
| 17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
| 18 | #include <linux/smp.h> | 18 | #include <linux/smp.h> |
| 19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
| 20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 21 | #include <linux/signal.h> | 21 | #include <linux/signal.h> |
| 22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
| 23 | #include <linux/wait.h> | 23 | #include <linux/wait.h> |
| 24 | #include <linux/ptrace.h> | 24 | #include <linux/ptrace.h> |
| 25 | #include <linux/unistd.h> | 25 | #include <linux/unistd.h> |
| 26 | #include <linux/stddef.h> | 26 | #include <linux/stddef.h> |
| 27 | #include <linux/compat.h> | 27 | #include <linux/compat.h> |
| 28 | #include <linux/elf.h> | 28 | #include <linux/elf.h> |
| 29 | #include <linux/personality.h> | 29 | #include <linux/personality.h> |
| 30 | #include <asm/ucontext.h> | 30 | #include <asm/ucontext.h> |
| 31 | #include <asm/rt_sigframe.h> | 31 | #include <asm/rt_sigframe.h> |
| 32 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 33 | #include <asm/pgalloc.h> | 33 | #include <asm/pgalloc.h> |
| 34 | #include <asm/cacheflush.h> | 34 | #include <asm/cacheflush.h> |
| 35 | #include <asm/asm-offsets.h> | 35 | #include <asm/asm-offsets.h> |
| 36 | 36 | ||
| 37 | #ifdef CONFIG_COMPAT | 37 | #ifdef CONFIG_COMPAT |
| 38 | #include <linux/compat.h> | 38 | #include <linux/compat.h> |
| 39 | #include "signal32.h" | 39 | #include "signal32.h" |
| 40 | #endif | 40 | #endif |
| 41 | 41 | ||
| 42 | #define DEBUG_SIG 0 | 42 | #define DEBUG_SIG 0 |
| 43 | #define DEBUG_SIG_LEVEL 2 | 43 | #define DEBUG_SIG_LEVEL 2 |
| 44 | 44 | ||
| 45 | #if DEBUG_SIG | 45 | #if DEBUG_SIG |
| 46 | #define DBG(LEVEL, ...) \ | 46 | #define DBG(LEVEL, ...) \ |
| 47 | ((DEBUG_SIG_LEVEL >= LEVEL) \ | 47 | ((DEBUG_SIG_LEVEL >= LEVEL) \ |
| 48 | ? printk(__VA_ARGS__) : (void) 0) | 48 | ? printk(__VA_ARGS__) : (void) 0) |
| 49 | #else | 49 | #else |
| 50 | #define DBG(LEVEL, ...) | 50 | #define DBG(LEVEL, ...) |
| 51 | #endif | 51 | #endif |
| 52 | 52 | ||
| 53 | 53 | ||
| 54 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 54 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 55 | 55 | ||
| 56 | /* gcc will complain if a pointer is cast to an integer of different | 56 | /* gcc will complain if a pointer is cast to an integer of different |
| 57 | * size. If you really need to do this (and we do for an ELF32 user | 57 | * size. If you really need to do this (and we do for an ELF32 user |
| 58 | * application in an ELF64 kernel) then you have to do a cast to an | 58 | * application in an ELF64 kernel) then you have to do a cast to an |
| 59 | * integer of the same size first. The A() macro accomplishes | 59 | * integer of the same size first. The A() macro accomplishes |
| 60 | * this. */ | 60 | * this. */ |
| 61 | #define A(__x) ((unsigned long)(__x)) | 61 | #define A(__x) ((unsigned long)(__x)) |
| 62 | 62 | ||
| 63 | int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall); | 63 | int do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall); |
| 64 | 64 | ||
| 65 | /* | 65 | /* |
| 66 | * Atomically swap in the new signal mask, and wait for a signal. | 66 | * Atomically swap in the new signal mask, and wait for a signal. |
| 67 | */ | 67 | */ |
| 68 | #ifdef __LP64__ | 68 | #ifdef __LP64__ |
| 69 | #include "sys32.h" | 69 | #include "sys32.h" |
| 70 | #endif | 70 | #endif |
| 71 | 71 | ||
| 72 | asmlinkage int | 72 | asmlinkage int |
| 73 | sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs) | 73 | sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs) |
| 74 | { | 74 | { |
| 75 | sigset_t saveset, newset; | 75 | sigset_t saveset, newset; |
| 76 | #ifdef __LP64__ | 76 | #ifdef __LP64__ |
| 77 | compat_sigset_t newset32; | 77 | compat_sigset_t newset32; |
| 78 | 78 | ||
| 79 | if(personality(current->personality) == PER_LINUX32){ | 79 | if(personality(current->personality) == PER_LINUX32){ |
| 80 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 80 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
| 81 | if (sigsetsize != sizeof(compat_sigset_t)) | 81 | if (sigsetsize != sizeof(compat_sigset_t)) |
| 82 | return -EINVAL; | 82 | return -EINVAL; |
| 83 | if (copy_from_user(&newset32, (compat_sigset_t __user *)unewset, sizeof(newset32))) | 83 | if (copy_from_user(&newset32, (compat_sigset_t __user *)unewset, sizeof(newset32))) |
| 84 | return -EFAULT; | 84 | return -EFAULT; |
| 85 | sigset_32to64(&newset,&newset32); | 85 | sigset_32to64(&newset,&newset32); |
| 86 | 86 | ||
| 87 | } else | 87 | } else |
| 88 | #endif | 88 | #endif |
| 89 | { | 89 | { |
| 90 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 90 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
| 91 | if (sigsetsize != sizeof(sigset_t)) | 91 | if (sigsetsize != sizeof(sigset_t)) |
| 92 | return -EINVAL; | 92 | return -EINVAL; |
| 93 | 93 | ||
| 94 | if (copy_from_user(&newset, unewset, sizeof(newset))) | 94 | if (copy_from_user(&newset, unewset, sizeof(newset))) |
| 95 | return -EFAULT; | 95 | return -EFAULT; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | sigdelsetmask(&newset, ~_BLOCKABLE); | 98 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 99 | 99 | ||
| 100 | spin_lock_irq(¤t->sighand->siglock); | 100 | spin_lock_irq(¤t->sighand->siglock); |
| 101 | saveset = current->blocked; | 101 | saveset = current->blocked; |
| 102 | current->blocked = newset; | 102 | current->blocked = newset; |
| 103 | recalc_sigpending(); | 103 | recalc_sigpending(); |
| 104 | spin_unlock_irq(¤t->sighand->siglock); | 104 | spin_unlock_irq(¤t->sighand->siglock); |
| 105 | 105 | ||
| 106 | regs->gr[28] = -EINTR; | 106 | regs->gr[28] = -EINTR; |
| 107 | while (1) { | 107 | while (1) { |
| 108 | current->state = TASK_INTERRUPTIBLE; | 108 | current->state = TASK_INTERRUPTIBLE; |
| 109 | schedule(); | 109 | schedule(); |
| 110 | if (do_signal(&saveset, regs, 1)) | 110 | if (do_signal(&saveset, regs, 1)) |
| 111 | return -EINTR; | 111 | return -EINTR; |
| 112 | } | 112 | } |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | /* | 115 | /* |
| 116 | * Do a signal return - restore sigcontext. | 116 | * Do a signal return - restore sigcontext. |
| 117 | */ | 117 | */ |
| 118 | 118 | ||
| 119 | /* Trampoline for calling rt_sigreturn() */ | 119 | /* Trampoline for calling rt_sigreturn() */ |
| 120 | #define INSN_LDI_R25_0 0x34190000 /* ldi 0,%r25 (in_syscall=0) */ | 120 | #define INSN_LDI_R25_0 0x34190000 /* ldi 0,%r25 (in_syscall=0) */ |
| 121 | #define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */ | 121 | #define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */ |
| 122 | #define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */ | 122 | #define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */ |
| 123 | #define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */ | 123 | #define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */ |
| 124 | #define INSN_NOP 0x08000240 /* nop */ | 124 | #define INSN_NOP 0x08000240 /* nop */ |
| 125 | /* For debugging */ | 125 | /* For debugging */ |
| 126 | #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */ | 126 | #define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */ |
| 127 | 127 | ||
| 128 | static long | 128 | static long |
| 129 | restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs) | 129 | restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs) |
| 130 | { | 130 | { |
| 131 | long err = 0; | 131 | long err = 0; |
| 132 | 132 | ||
| 133 | err |= __copy_from_user(regs->gr, sc->sc_gr, sizeof(regs->gr)); | 133 | err |= __copy_from_user(regs->gr, sc->sc_gr, sizeof(regs->gr)); |
| 134 | err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr)); | 134 | err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr)); |
| 135 | err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq)); | 135 | err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq)); |
| 136 | err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq)); | 136 | err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq)); |
| 137 | err |= __get_user(regs->sar, &sc->sc_sar); | 137 | err |= __get_user(regs->sar, &sc->sc_sar); |
| 138 | DBG(2,"restore_sigcontext: iaoq is 0x%#lx / 0x%#lx\n", | 138 | DBG(2,"restore_sigcontext: iaoq is 0x%#lx / 0x%#lx\n", |
| 139 | regs->iaoq[0],regs->iaoq[1]); | 139 | regs->iaoq[0],regs->iaoq[1]); |
| 140 | DBG(2,"restore_sigcontext: r28 is %ld\n", regs->gr[28]); | 140 | DBG(2,"restore_sigcontext: r28 is %ld\n", regs->gr[28]); |
| 141 | return err; | 141 | return err; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | void | 144 | void |
| 145 | sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) | 145 | sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) |
| 146 | { | 146 | { |
| 147 | struct rt_sigframe __user *frame; | 147 | struct rt_sigframe __user *frame; |
| 148 | struct siginfo si; | 148 | struct siginfo si; |
| 149 | sigset_t set; | 149 | sigset_t set; |
| 150 | unsigned long usp = (regs->gr[30] & ~(0x01UL)); | 150 | unsigned long usp = (regs->gr[30] & ~(0x01UL)); |
| 151 | unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE; | 151 | unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE; |
| 152 | #ifdef __LP64__ | 152 | #ifdef __LP64__ |
| 153 | compat_sigset_t compat_set; | 153 | compat_sigset_t compat_set; |
| 154 | struct compat_rt_sigframe __user * compat_frame; | 154 | struct compat_rt_sigframe __user * compat_frame; |
| 155 | 155 | ||
| 156 | if(personality(current->personality) == PER_LINUX32) | 156 | if(personality(current->personality) == PER_LINUX32) |
| 157 | sigframe_size = PARISC_RT_SIGFRAME_SIZE32; | 157 | sigframe_size = PARISC_RT_SIGFRAME_SIZE32; |
| 158 | #endif | 158 | #endif |
| 159 | 159 | ||
| 160 | 160 | ||
| 161 | /* Unwind the user stack to get the rt_sigframe structure. */ | 161 | /* Unwind the user stack to get the rt_sigframe structure. */ |
| 162 | frame = (struct rt_sigframe __user *) | 162 | frame = (struct rt_sigframe __user *) |
| 163 | (usp - sigframe_size); | 163 | (usp - sigframe_size); |
| 164 | DBG(2,"sys_rt_sigreturn: frame is %p\n", frame); | 164 | DBG(2,"sys_rt_sigreturn: frame is %p\n", frame); |
| 165 | 165 | ||
| 166 | #ifdef __LP64__ | 166 | #ifdef __LP64__ |
| 167 | compat_frame = (struct compat_rt_sigframe __user *)frame; | 167 | compat_frame = (struct compat_rt_sigframe __user *)frame; |
| 168 | 168 | ||
| 169 | if(personality(current->personality) == PER_LINUX32){ | 169 | if(personality(current->personality) == PER_LINUX32){ |
| 170 | DBG(2,"sys_rt_sigreturn: ELF32 process.\n"); | 170 | DBG(2,"sys_rt_sigreturn: ELF32 process.\n"); |
| 171 | if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask, sizeof(compat_set))) | 171 | if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask, sizeof(compat_set))) |
| 172 | goto give_sigsegv; | 172 | goto give_sigsegv; |
| 173 | sigset_32to64(&set,&compat_set); | 173 | sigset_32to64(&set,&compat_set); |
| 174 | } else | 174 | } else |
| 175 | #endif | 175 | #endif |
| 176 | { | 176 | { |
| 177 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 177 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| 178 | goto give_sigsegv; | 178 | goto give_sigsegv; |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | sigdelsetmask(&set, ~_BLOCKABLE); | 181 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 182 | spin_lock_irq(¤t->sighand->siglock); | 182 | spin_lock_irq(¤t->sighand->siglock); |
| 183 | current->blocked = set; | 183 | current->blocked = set; |
| 184 | recalc_sigpending(); | 184 | recalc_sigpending(); |
| 185 | spin_unlock_irq(¤t->sighand->siglock); | 185 | spin_unlock_irq(¤t->sighand->siglock); |
| 186 | 186 | ||
| 187 | /* Good thing we saved the old gr[30], eh? */ | 187 | /* Good thing we saved the old gr[30], eh? */ |
| 188 | #ifdef __LP64__ | 188 | #ifdef __LP64__ |
| 189 | if(personality(current->personality) == PER_LINUX32){ | 189 | if(personality(current->personality) == PER_LINUX32){ |
| 190 | DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n", | 190 | DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n", |
| 191 | &compat_frame->uc.uc_mcontext); | 191 | &compat_frame->uc.uc_mcontext); |
| 192 | // FIXME: Load upper half from register file | 192 | // FIXME: Load upper half from register file |
| 193 | if (restore_sigcontext32(&compat_frame->uc.uc_mcontext, | 193 | if (restore_sigcontext32(&compat_frame->uc.uc_mcontext, |
| 194 | &compat_frame->regs, regs)) | 194 | &compat_frame->regs, regs)) |
| 195 | goto give_sigsegv; | 195 | goto give_sigsegv; |
| 196 | DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", | 196 | DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", |
| 197 | usp, &compat_frame->uc.uc_stack); | 197 | usp, &compat_frame->uc.uc_stack); |
| 198 | if (do_sigaltstack32(&compat_frame->uc.uc_stack, NULL, usp) == -EFAULT) | 198 | if (do_sigaltstack32(&compat_frame->uc.uc_stack, NULL, usp) == -EFAULT) |
| 199 | goto give_sigsegv; | 199 | goto give_sigsegv; |
| 200 | } else | 200 | } else |
| 201 | #endif | 201 | #endif |
| 202 | { | 202 | { |
| 203 | DBG(1,"sys_rt_sigreturn: frame->uc.uc_mcontext 0x%p\n", | 203 | DBG(1,"sys_rt_sigreturn: frame->uc.uc_mcontext 0x%p\n", |
| 204 | &frame->uc.uc_mcontext); | 204 | &frame->uc.uc_mcontext); |
| 205 | if (restore_sigcontext(&frame->uc.uc_mcontext, regs)) | 205 | if (restore_sigcontext(&frame->uc.uc_mcontext, regs)) |
| 206 | goto give_sigsegv; | 206 | goto give_sigsegv; |
| 207 | DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", | 207 | DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n", |
| 208 | usp, &frame->uc.uc_stack); | 208 | usp, &frame->uc.uc_stack); |
| 209 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT) | 209 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT) |
| 210 | goto give_sigsegv; | 210 | goto give_sigsegv; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | 213 | ||
| 214 | 214 | ||
| 215 | /* If we are on the syscall path IAOQ will not be restored, and | 215 | /* If we are on the syscall path IAOQ will not be restored, and |
| 216 | * if we are on the interrupt path we must not corrupt gr31. | 216 | * if we are on the interrupt path we must not corrupt gr31. |
| 217 | */ | 217 | */ |
| 218 | if (in_syscall) | 218 | if (in_syscall) |
| 219 | regs->gr[31] = regs->iaoq[0]; | 219 | regs->gr[31] = regs->iaoq[0]; |
| 220 | #if DEBUG_SIG | 220 | #if DEBUG_SIG |
| 221 | DBG(1,"sys_rt_sigreturn: returning to %#lx, DUMPING REGS:\n", regs->iaoq[0]); | 221 | DBG(1,"sys_rt_sigreturn: returning to %#lx, DUMPING REGS:\n", regs->iaoq[0]); |
| 222 | show_regs(regs); | 222 | show_regs(regs); |
| 223 | #endif | 223 | #endif |
| 224 | return; | 224 | return; |
| 225 | 225 | ||
| 226 | give_sigsegv: | 226 | give_sigsegv: |
| 227 | DBG(1,"sys_rt_sigreturn: Sending SIGSEGV\n"); | 227 | DBG(1,"sys_rt_sigreturn: Sending SIGSEGV\n"); |
| 228 | si.si_signo = SIGSEGV; | 228 | si.si_signo = SIGSEGV; |
| 229 | si.si_errno = 0; | 229 | si.si_errno = 0; |
| 230 | si.si_code = SI_KERNEL; | 230 | si.si_code = SI_KERNEL; |
| 231 | si.si_pid = current->pid; | 231 | si.si_pid = current->pid; |
| 232 | si.si_uid = current->uid; | 232 | si.si_uid = current->uid; |
| 233 | si.si_addr = &frame->uc; | 233 | si.si_addr = &frame->uc; |
| 234 | force_sig_info(SIGSEGV, &si, current); | 234 | force_sig_info(SIGSEGV, &si, current); |
| 235 | return; | 235 | return; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | /* | 238 | /* |
| 239 | * Set up a signal frame. | 239 | * Set up a signal frame. |
| 240 | */ | 240 | */ |
| 241 | 241 | ||
| 242 | static inline void __user * | 242 | static inline void __user * |
| 243 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | 243 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) |
| 244 | { | 244 | { |
| 245 | /*FIXME: ELF32 vs. ELF64 has different frame_size, but since we | 245 | /*FIXME: ELF32 vs. ELF64 has different frame_size, but since we |
| 246 | don't use the parameter it doesn't matter */ | 246 | don't use the parameter it doesn't matter */ |
| 247 | 247 | ||
| 248 | DBG(1,"get_sigframe: ka = %#lx, sp = %#lx, frame_size = %#lx\n", | 248 | DBG(1,"get_sigframe: ka = %#lx, sp = %#lx, frame_size = %#lx\n", |
| 249 | (unsigned long)ka, sp, frame_size); | 249 | (unsigned long)ka, sp, frame_size); |
| 250 | 250 | ||
| 251 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) | 251 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) |
| 252 | sp = current->sas_ss_sp; /* Stacks grow up! */ | 252 | sp = current->sas_ss_sp; /* Stacks grow up! */ |
| 253 | 253 | ||
| 254 | DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp); | 254 | DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp); |
| 255 | return (void __user *) sp; /* Stacks grow up. Fun. */ | 255 | return (void __user *) sp; /* Stacks grow up. Fun. */ |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | static long | 258 | static long |
| 259 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, int in_syscall) | 259 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, int in_syscall) |
| 260 | 260 | ||
| 261 | { | 261 | { |
| 262 | unsigned long flags = 0; | 262 | unsigned long flags = 0; |
| 263 | long err = 0; | 263 | long err = 0; |
| 264 | 264 | ||
| 265 | if (on_sig_stack((unsigned long) sc)) | 265 | if (on_sig_stack((unsigned long) sc)) |
| 266 | flags |= PARISC_SC_FLAG_ONSTACK; | 266 | flags |= PARISC_SC_FLAG_ONSTACK; |
| 267 | if (in_syscall) { | 267 | if (in_syscall) { |
| 268 | flags |= PARISC_SC_FLAG_IN_SYSCALL; | 268 | flags |= PARISC_SC_FLAG_IN_SYSCALL; |
| 269 | /* regs->iaoq is undefined in the syscall return path */ | 269 | /* regs->iaoq is undefined in the syscall return path */ |
| 270 | err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]); | 270 | err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]); |
| 271 | err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]); | 271 | err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]); |
| 272 | err |= __put_user(regs->sr[3], &sc->sc_iasq[0]); | 272 | err |= __put_user(regs->sr[3], &sc->sc_iasq[0]); |
| 273 | err |= __put_user(regs->sr[3], &sc->sc_iasq[1]); | 273 | err |= __put_user(regs->sr[3], &sc->sc_iasq[1]); |
| 274 | DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (in syscall)\n", | 274 | DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (in syscall)\n", |
| 275 | regs->gr[31], regs->gr[31]+4); | 275 | regs->gr[31], regs->gr[31]+4); |
| 276 | } else { | 276 | } else { |
| 277 | err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq)); | 277 | err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq)); |
| 278 | err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq)); | 278 | err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq)); |
| 279 | DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (not in syscall)\n", | 279 | DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (not in syscall)\n", |
| 280 | regs->iaoq[0], regs->iaoq[1]); | 280 | regs->iaoq[0], regs->iaoq[1]); |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | err |= __put_user(flags, &sc->sc_flags); | 283 | err |= __put_user(flags, &sc->sc_flags); |
| 284 | err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr)); | 284 | err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr)); |
| 285 | err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr)); | 285 | err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr)); |
| 286 | err |= __put_user(regs->sar, &sc->sc_sar); | 286 | err |= __put_user(regs->sar, &sc->sc_sar); |
| 287 | DBG(1,"setup_sigcontext: r28 is %ld\n", regs->gr[28]); | 287 | DBG(1,"setup_sigcontext: r28 is %ld\n", regs->gr[28]); |
| 288 | 288 | ||
| 289 | return err; | 289 | return err; |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | static long | 292 | static long |
| 293 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 293 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 294 | sigset_t *set, struct pt_regs *regs, int in_syscall) | 294 | sigset_t *set, struct pt_regs *regs, int in_syscall) |
| 295 | { | 295 | { |
| 296 | struct rt_sigframe __user *frame; | 296 | struct rt_sigframe __user *frame; |
| 297 | unsigned long rp, usp; | 297 | unsigned long rp, usp; |
| 298 | unsigned long haddr, sigframe_size; | 298 | unsigned long haddr, sigframe_size; |
| 299 | int err = 0; | 299 | int err = 0; |
| 300 | #ifdef __LP64__ | 300 | #ifdef __LP64__ |
| 301 | compat_int_t compat_val; | 301 | compat_int_t compat_val; |
| 302 | struct compat_rt_sigframe __user * compat_frame; | 302 | struct compat_rt_sigframe __user * compat_frame; |
| 303 | compat_sigset_t compat_set; | 303 | compat_sigset_t compat_set; |
| 304 | #endif | 304 | #endif |
| 305 | 305 | ||
| 306 | usp = (regs->gr[30] & ~(0x01UL)); | 306 | usp = (regs->gr[30] & ~(0x01UL)); |
| 307 | /*FIXME: frame_size parameter is unused, remove it. */ | 307 | /*FIXME: frame_size parameter is unused, remove it. */ |
| 308 | frame = get_sigframe(ka, usp, sizeof(*frame)); | 308 | frame = get_sigframe(ka, usp, sizeof(*frame)); |
| 309 | 309 | ||
| 310 | DBG(1,"SETUP_RT_FRAME: START\n"); | 310 | DBG(1,"SETUP_RT_FRAME: START\n"); |
| 311 | DBG(1,"setup_rt_frame: frame %p info %p\n", frame, info); | 311 | DBG(1,"setup_rt_frame: frame %p info %p\n", frame, info); |
| 312 | 312 | ||
| 313 | 313 | ||
| 314 | #ifdef __LP64__ | 314 | #ifdef __LP64__ |
| 315 | 315 | ||
| 316 | compat_frame = (struct compat_rt_sigframe __user *)frame; | 316 | compat_frame = (struct compat_rt_sigframe __user *)frame; |
| 317 | 317 | ||
| 318 | if(personality(current->personality) == PER_LINUX32) { | 318 | if(personality(current->personality) == PER_LINUX32) { |
| 319 | DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info); | 319 | DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info); |
| 320 | err |= copy_siginfo_to_user32(&compat_frame->info, info); | 320 | err |= copy_siginfo_to_user32(&compat_frame->info, info); |
| 321 | DBG(1,"SETUP_RT_FRAME: 1\n"); | 321 | DBG(1,"SETUP_RT_FRAME: 1\n"); |
| 322 | compat_val = (compat_int_t)current->sas_ss_sp; | 322 | compat_val = (compat_int_t)current->sas_ss_sp; |
| 323 | err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp); | 323 | err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp); |
| 324 | DBG(1,"SETUP_RT_FRAME: 2\n"); | 324 | DBG(1,"SETUP_RT_FRAME: 2\n"); |
| 325 | compat_val = (compat_int_t)current->sas_ss_size; | 325 | compat_val = (compat_int_t)current->sas_ss_size; |
| 326 | err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_size); | 326 | err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_size); |
| 327 | DBG(1,"SETUP_RT_FRAME: 3\n"); | 327 | DBG(1,"SETUP_RT_FRAME: 3\n"); |
| 328 | compat_val = sas_ss_flags(regs->gr[30]); | 328 | compat_val = sas_ss_flags(regs->gr[30]); |
| 329 | err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_flags); | 329 | err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_flags); |
| 330 | DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &compat_frame->uc); | 330 | DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &compat_frame->uc); |
| 331 | DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext); | 331 | DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext); |
| 332 | err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext, | 332 | err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext, |
| 333 | &compat_frame->regs, regs, in_syscall); | 333 | &compat_frame->regs, regs, in_syscall); |
| 334 | sigset_64to32(&compat_set,set); | 334 | sigset_64to32(&compat_set,set); |
| 335 | err |= __copy_to_user(&compat_frame->uc.uc_sigmask, &compat_set, sizeof(compat_set)); | 335 | err |= __copy_to_user(&compat_frame->uc.uc_sigmask, &compat_set, sizeof(compat_set)); |
| 336 | } else | 336 | } else |
| 337 | #endif | 337 | #endif |
| 338 | { | 338 | { |
| 339 | DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &frame->info); | 339 | DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &frame->info); |
| 340 | err |= copy_siginfo_to_user(&frame->info, info); | 340 | err |= copy_siginfo_to_user(&frame->info, info); |
| 341 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 341 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
| 342 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 342 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
| 343 | err |= __put_user(sas_ss_flags(regs->gr[30]), | 343 | err |= __put_user(sas_ss_flags(regs->gr[30]), |
| 344 | &frame->uc.uc_stack.ss_flags); | 344 | &frame->uc.uc_stack.ss_flags); |
| 345 | DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &frame->uc); | 345 | DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &frame->uc); |
| 346 | DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &frame->uc.uc_mcontext); | 346 | DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &frame->uc.uc_mcontext); |
| 347 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall); | 347 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall); |
| 348 | /* FIXME: Should probably be converted aswell for the compat case */ | 348 | /* FIXME: Should probably be converted aswell for the compat case */ |
| 349 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 349 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | if (err) | 352 | if (err) |
| 353 | goto give_sigsegv; | 353 | goto give_sigsegv; |
| 354 | 354 | ||
| 355 | /* Set up to return from userspace. If provided, use a stub | 355 | /* Set up to return from userspace. If provided, use a stub |
| 356 | already in userspace. The first words of tramp are used to | 356 | already in userspace. The first words of tramp are used to |
| 357 | save the previous sigrestartblock trampoline that might be | 357 | save the previous sigrestartblock trampoline that might be |
| 358 | on the stack. We start the sigreturn trampoline at | 358 | on the stack. We start the sigreturn trampoline at |
| 359 | SIGRESTARTBLOCK_TRAMP+X. */ | 359 | SIGRESTARTBLOCK_TRAMP+X. */ |
| 360 | err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0, | 360 | err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0, |
| 361 | &frame->tramp[SIGRESTARTBLOCK_TRAMP+0]); | 361 | &frame->tramp[SIGRESTARTBLOCK_TRAMP+0]); |
| 362 | err |= __put_user(INSN_LDI_R20, | 362 | err |= __put_user(INSN_LDI_R20, |
| 363 | &frame->tramp[SIGRESTARTBLOCK_TRAMP+1]); | 363 | &frame->tramp[SIGRESTARTBLOCK_TRAMP+1]); |
| 364 | err |= __put_user(INSN_BLE_SR2_R0, | 364 | err |= __put_user(INSN_BLE_SR2_R0, |
| 365 | &frame->tramp[SIGRESTARTBLOCK_TRAMP+2]); | 365 | &frame->tramp[SIGRESTARTBLOCK_TRAMP+2]); |
| 366 | err |= __put_user(INSN_NOP, &frame->tramp[SIGRESTARTBLOCK_TRAMP+3]); | 366 | err |= __put_user(INSN_NOP, &frame->tramp[SIGRESTARTBLOCK_TRAMP+3]); |
| 367 | 367 | ||
| 368 | #if DEBUG_SIG | 368 | #if DEBUG_SIG |
| 369 | /* Assert that we're flushing in the correct space... */ | 369 | /* Assert that we're flushing in the correct space... */ |
| 370 | { | 370 | { |
| 371 | int sid; | 371 | int sid; |
| 372 | asm ("mfsp %%sr3,%0" : "=r" (sid)); | 372 | asm ("mfsp %%sr3,%0" : "=r" (sid)); |
| 373 | DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n", | 373 | DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n", |
| 374 | sid, frame->tramp); | 374 | sid, frame->tramp); |
| 375 | } | 375 | } |
| 376 | #endif | 376 | #endif |
| 377 | 377 | ||
| 378 | flush_user_dcache_range((unsigned long) &frame->tramp[0], | 378 | flush_user_dcache_range((unsigned long) &frame->tramp[0], |
| 379 | (unsigned long) &frame->tramp[TRAMP_SIZE]); | 379 | (unsigned long) &frame->tramp[TRAMP_SIZE]); |
| 380 | flush_user_icache_range((unsigned long) &frame->tramp[0], | 380 | flush_user_icache_range((unsigned long) &frame->tramp[0], |
| 381 | (unsigned long) &frame->tramp[TRAMP_SIZE]); | 381 | (unsigned long) &frame->tramp[TRAMP_SIZE]); |
| 382 | 382 | ||
| 383 | /* TRAMP Words 0-4, Lenght 5 = SIGRESTARTBLOCK_TRAMP | 383 | /* TRAMP Words 0-4, Lenght 5 = SIGRESTARTBLOCK_TRAMP |
| 384 | * TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP | 384 | * TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP |
| 385 | * So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP | 385 | * So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP |
| 386 | */ | 386 | */ |
| 387 | rp = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP]; | 387 | rp = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP]; |
| 388 | 388 | ||
| 389 | if (err) | 389 | if (err) |
| 390 | goto give_sigsegv; | 390 | goto give_sigsegv; |
| 391 | 391 | ||
| 392 | haddr = A(ka->sa.sa_handler); | 392 | haddr = A(ka->sa.sa_handler); |
| 393 | /* The sa_handler may be a pointer to a function descriptor */ | 393 | /* The sa_handler may be a pointer to a function descriptor */ |
| 394 | #ifdef __LP64__ | 394 | #ifdef __LP64__ |
| 395 | if(personality(current->personality) == PER_LINUX32) { | 395 | if(personality(current->personality) == PER_LINUX32) { |
| 396 | #endif | 396 | #endif |
| 397 | if (haddr & PA_PLABEL_FDESC) { | 397 | if (haddr & PA_PLABEL_FDESC) { |
| 398 | Elf32_Fdesc fdesc; | 398 | Elf32_Fdesc fdesc; |
| 399 | Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3); | 399 | Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3); |
| 400 | 400 | ||
| 401 | err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); | 401 | err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); |
| 402 | 402 | ||
| 403 | if (err) | 403 | if (err) |
| 404 | goto give_sigsegv; | 404 | goto give_sigsegv; |
| 405 | 405 | ||
| 406 | haddr = fdesc.addr; | 406 | haddr = fdesc.addr; |
| 407 | regs->gr[19] = fdesc.gp; | 407 | regs->gr[19] = fdesc.gp; |
| 408 | } | 408 | } |
| 409 | #ifdef __LP64__ | 409 | #ifdef __LP64__ |
| 410 | } else { | 410 | } else { |
| 411 | Elf64_Fdesc fdesc; | 411 | Elf64_Fdesc fdesc; |
| 412 | Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3); | 412 | Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3); |
| 413 | 413 | ||
| 414 | err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); | 414 | err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc)); |
| 415 | 415 | ||
| 416 | if (err) | 416 | if (err) |
| 417 | goto give_sigsegv; | 417 | goto give_sigsegv; |
| 418 | 418 | ||
| 419 | haddr = fdesc.addr; | 419 | haddr = fdesc.addr; |
| 420 | regs->gr[19] = fdesc.gp; | 420 | regs->gr[19] = fdesc.gp; |
| 421 | DBG(1,"setup_rt_frame: 64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n", | 421 | DBG(1,"setup_rt_frame: 64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n", |
| 422 | haddr, regs->gr[19], in_syscall); | 422 | haddr, regs->gr[19], in_syscall); |
| 423 | } | 423 | } |
| 424 | #endif | 424 | #endif |
| 425 | 425 | ||
| 426 | /* The syscall return path will create IAOQ values from r31. | 426 | /* The syscall return path will create IAOQ values from r31. |
| 427 | */ | 427 | */ |
| 428 | sigframe_size = PARISC_RT_SIGFRAME_SIZE; | 428 | sigframe_size = PARISC_RT_SIGFRAME_SIZE; |
| 429 | #ifdef __LP64__ | 429 | #ifdef __LP64__ |
| 430 | if(personality(current->personality) == PER_LINUX32) | 430 | if(personality(current->personality) == PER_LINUX32) |
| 431 | sigframe_size = PARISC_RT_SIGFRAME_SIZE32; | 431 | sigframe_size = PARISC_RT_SIGFRAME_SIZE32; |
| 432 | #endif | 432 | #endif |
| 433 | if (in_syscall) { | 433 | if (in_syscall) { |
| 434 | regs->gr[31] = haddr; | 434 | regs->gr[31] = haddr; |
| 435 | #ifdef __LP64__ | 435 | #ifdef __LP64__ |
| 436 | if(personality(current->personality) == PER_LINUX) | 436 | if(personality(current->personality) == PER_LINUX) |
| 437 | sigframe_size |= 1; | 437 | sigframe_size |= 1; |
| 438 | #endif | 438 | #endif |
| 439 | } else { | 439 | } else { |
| 440 | unsigned long psw = USER_PSW; | 440 | unsigned long psw = USER_PSW; |
| 441 | #ifdef __LP64__ | 441 | #ifdef __LP64__ |
| 442 | if(personality(current->personality) == PER_LINUX) | 442 | if(personality(current->personality) == PER_LINUX) |
| 443 | psw |= PSW_W; | 443 | psw |= PSW_W; |
| 444 | #endif | 444 | #endif |
| 445 | 445 | ||
| 446 | /* If we are singlestepping, arrange a trap to be delivered | 446 | /* If we are singlestepping, arrange a trap to be delivered |
| 447 | when we return to userspace. Note the semantics -- we | 447 | when we return to userspace. Note the semantics -- we |
| 448 | should trap before the first insn in the handler is | 448 | should trap before the first insn in the handler is |
| 449 | executed. Ref: | 449 | executed. Ref: |
| 450 | http://sources.redhat.com/ml/gdb/2004-11/msg00245.html | 450 | http://sources.redhat.com/ml/gdb/2004-11/msg00245.html |
| 451 | */ | 451 | */ |
| 452 | if (pa_psw(current)->r) { | 452 | if (pa_psw(current)->r) { |
| 453 | pa_psw(current)->r = 0; | 453 | pa_psw(current)->r = 0; |
| 454 | psw |= PSW_R; | 454 | psw |= PSW_R; |
| 455 | mtctl(-1, 0); | 455 | mtctl(-1, 0); |
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | regs->gr[0] = psw; | 458 | regs->gr[0] = psw; |
| 459 | regs->iaoq[0] = haddr | 3; | 459 | regs->iaoq[0] = haddr | 3; |
| 460 | regs->iaoq[1] = regs->iaoq[0] + 4; | 460 | regs->iaoq[1] = regs->iaoq[0] + 4; |
| 461 | } | 461 | } |
| 462 | 462 | ||
| 463 | regs->gr[2] = rp; /* userland return pointer */ | 463 | regs->gr[2] = rp; /* userland return pointer */ |
| 464 | regs->gr[26] = sig; /* signal number */ | 464 | regs->gr[26] = sig; /* signal number */ |
| 465 | 465 | ||
| 466 | #ifdef __LP64__ | 466 | #ifdef __LP64__ |
| 467 | if(personality(current->personality) == PER_LINUX32){ | 467 | if(personality(current->personality) == PER_LINUX32){ |
| 468 | regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */ | 468 | regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */ |
| 469 | regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */ | 469 | regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */ |
| 470 | } else | 470 | } else |
| 471 | #endif | 471 | #endif |
| 472 | { | 472 | { |
| 473 | regs->gr[25] = A(&frame->info); /* siginfo pointer */ | 473 | regs->gr[25] = A(&frame->info); /* siginfo pointer */ |
| 474 | regs->gr[24] = A(&frame->uc); /* ucontext pointer */ | 474 | regs->gr[24] = A(&frame->uc); /* ucontext pointer */ |
| 475 | } | 475 | } |
| 476 | 476 | ||
| 477 | DBG(1,"setup_rt_frame: making sigreturn frame: %#lx + %#lx = %#lx\n", | 477 | DBG(1,"setup_rt_frame: making sigreturn frame: %#lx + %#lx = %#lx\n", |
| 478 | regs->gr[30], sigframe_size, | 478 | regs->gr[30], sigframe_size, |
| 479 | regs->gr[30] + sigframe_size); | 479 | regs->gr[30] + sigframe_size); |
| 480 | /* Raise the user stack pointer to make a proper call frame. */ | 480 | /* Raise the user stack pointer to make a proper call frame. */ |
| 481 | regs->gr[30] = (A(frame) + sigframe_size); | 481 | regs->gr[30] = (A(frame) + sigframe_size); |
| 482 | 482 | ||
| 483 | 483 | ||
| 484 | DBG(1,"setup_rt_frame: sig deliver (%s,%d) frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n", | 484 | DBG(1,"setup_rt_frame: sig deliver (%s,%d) frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n", |
| 485 | current->comm, current->pid, frame, regs->gr[30], | 485 | current->comm, current->pid, frame, regs->gr[30], |
| 486 | regs->iaoq[0], regs->iaoq[1], rp); | 486 | regs->iaoq[0], regs->iaoq[1], rp); |
| 487 | 487 | ||
| 488 | return 1; | 488 | return 1; |
| 489 | 489 | ||
| 490 | give_sigsegv: | 490 | give_sigsegv: |
| 491 | DBG(1,"setup_rt_frame: sending SIGSEGV\n"); | 491 | DBG(1,"setup_rt_frame: sending SIGSEGV\n"); |
| 492 | force_sigsegv(sig, current); | 492 | force_sigsegv(sig, current); |
| 493 | return 0; | 493 | return 0; |
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | /* | 496 | /* |
| 497 | * OK, we're invoking a handler. | 497 | * OK, we're invoking a handler. |
| 498 | */ | 498 | */ |
| 499 | 499 | ||
| 500 | static long | 500 | static long |
| 501 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 501 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
| 502 | sigset_t *oldset, struct pt_regs *regs, int in_syscall) | 502 | sigset_t *oldset, struct pt_regs *regs, int in_syscall) |
| 503 | { | 503 | { |
| 504 | DBG(1,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n", | 504 | DBG(1,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n", |
| 505 | sig, ka, info, oldset, regs); | 505 | sig, ka, info, oldset, regs); |
| 506 | 506 | ||
| 507 | /* Set up the stack frame */ | 507 | /* Set up the stack frame */ |
| 508 | if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) | 508 | if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) |
| 509 | return 0; | 509 | return 0; |
| 510 | 510 | ||
| 511 | spin_lock_irq(¤t->sighand->siglock); | 511 | spin_lock_irq(¤t->sighand->siglock); |
| 512 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 512 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
| 513 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 513 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 514 | sigaddset(¤t->blocked,sig); | 514 | sigaddset(¤t->blocked,sig); |
| 515 | recalc_sigpending(); | 515 | recalc_sigpending(); |
| 516 | spin_unlock_irq(¤t->sighand->siglock); | 516 | spin_unlock_irq(¤t->sighand->siglock); |
| 517 | return 1; | 517 | return 1; |
| 518 | } | 518 | } |
| 519 | 519 | ||
| 520 | /* | 520 | /* |
| 521 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 521 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 522 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 522 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 523 | * mistake. | 523 | * mistake. |
| 524 | * | 524 | * |
| 525 | * We need to be able to restore the syscall arguments (r21-r26) to | 525 | * We need to be able to restore the syscall arguments (r21-r26) to |
| 526 | * restart syscalls. Thus, the syscall path should save them in the | 526 | * restart syscalls. Thus, the syscall path should save them in the |
| 527 | * pt_regs structure (it's okay to do so since they are caller-save | 527 | * pt_regs structure (it's okay to do so since they are caller-save |
| 528 | * registers). As noted below, the syscall number gets restored for | 528 | * registers). As noted below, the syscall number gets restored for |
| 529 | * us due to the magic of delayed branching. | 529 | * us due to the magic of delayed branching. |
| 530 | */ | 530 | */ |
| 531 | 531 | ||
| 532 | asmlinkage int | 532 | asmlinkage int |
| 533 | do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) | 533 | do_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall) |
| 534 | { | 534 | { |
| 535 | siginfo_t info; | 535 | siginfo_t info; |
| 536 | struct k_sigaction ka; | 536 | struct k_sigaction ka; |
| 537 | int signr; | 537 | int signr; |
| 538 | 538 | ||
| 539 | DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n", | 539 | DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n", |
| 540 | oldset, regs, regs->sr[7], in_syscall); | 540 | oldset, regs, regs->sr[7], in_syscall); |
| 541 | 541 | ||
| 542 | /* Everyone else checks to see if they are in kernel mode at | 542 | /* Everyone else checks to see if they are in kernel mode at |
| 543 | this point and exits if that's the case. I'm not sure why | 543 | this point and exits if that's the case. I'm not sure why |
| 544 | we would be called in that case, but for some reason we | 544 | we would be called in that case, but for some reason we |
| 545 | are. */ | 545 | are. */ |
| 546 | 546 | ||
| 547 | if (!oldset) | 547 | if (!oldset) |
| 548 | oldset = ¤t->blocked; | 548 | oldset = ¤t->blocked; |
| 549 | 549 | ||
| 550 | DBG(1,"do_signal: oldset %08lx / %08lx\n", | 550 | DBG(1,"do_signal: oldset %08lx / %08lx\n", |
| 551 | oldset->sig[0], oldset->sig[1]); | 551 | oldset->sig[0], oldset->sig[1]); |
| 552 | 552 | ||
| 553 | 553 | ||
| 554 | /* May need to force signal if handle_signal failed to deliver */ | 554 | /* May need to force signal if handle_signal failed to deliver */ |
| 555 | while (1) { | 555 | while (1) { |
| 556 | 556 | ||
| 557 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 557 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 558 | DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); | 558 | DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); |
| 559 | 559 | ||
| 560 | if (signr <= 0) | 560 | if (signr <= 0) |
| 561 | break; | 561 | break; |
| 562 | 562 | ||
| 563 | /* Restart a system call if necessary. */ | 563 | /* Restart a system call if necessary. */ |
| 564 | if (in_syscall) { | 564 | if (in_syscall) { |
| 565 | /* Check the return code */ | 565 | /* Check the return code */ |
| 566 | switch (regs->gr[28]) { | 566 | switch (regs->gr[28]) { |
| 567 | case -ERESTART_RESTARTBLOCK: | 567 | case -ERESTART_RESTARTBLOCK: |
| 568 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | 568 | current_thread_info()->restart_block.fn = do_no_restart_syscall; |
| 569 | case -ERESTARTNOHAND: | 569 | case -ERESTARTNOHAND: |
| 570 | DBG(1,"ERESTARTNOHAND: returning -EINTR\n"); | 570 | DBG(1,"ERESTARTNOHAND: returning -EINTR\n"); |
| 571 | regs->gr[28] = -EINTR; | 571 | regs->gr[28] = -EINTR; |
| 572 | break; | 572 | break; |
| 573 | 573 | ||
| 574 | case -ERESTARTSYS: | 574 | case -ERESTARTSYS: |
| 575 | if (!(ka.sa.sa_flags & SA_RESTART)) { | 575 | if (!(ka.sa.sa_flags & SA_RESTART)) { |
| 576 | DBG(1,"ERESTARTSYS: putting -EINTR\n"); | 576 | DBG(1,"ERESTARTSYS: putting -EINTR\n"); |
| 577 | regs->gr[28] = -EINTR; | 577 | regs->gr[28] = -EINTR; |
| 578 | break; | 578 | break; |
| 579 | } | 579 | } |
| 580 | /* fallthrough */ | 580 | /* fallthrough */ |
| 581 | case -ERESTARTNOINTR: | 581 | case -ERESTARTNOINTR: |
| 582 | /* A syscall is just a branch, so all | 582 | /* A syscall is just a branch, so all |
| 583 | we have to do is fiddle the return pointer. */ | 583 | we have to do is fiddle the return pointer. */ |
| 584 | regs->gr[31] -= 8; /* delayed branching */ | 584 | regs->gr[31] -= 8; /* delayed branching */ |
| 585 | /* Preserve original r28. */ | 585 | /* Preserve original r28. */ |
| 586 | regs->gr[28] = regs->orig_r28; | 586 | regs->gr[28] = regs->orig_r28; |
| 587 | break; | 587 | break; |
| 588 | } | 588 | } |
| 589 | } | 589 | } |
| 590 | /* Whee! Actually deliver the signal. If the | 590 | /* Whee! Actually deliver the signal. If the |
| 591 | delivery failed, we need to continue to iterate in | 591 | delivery failed, we need to continue to iterate in |
| 592 | this loop so we can deliver the SIGSEGV... */ | 592 | this loop so we can deliver the SIGSEGV... */ |
| 593 | if (handle_signal(signr, &info, &ka, oldset, regs, in_syscall)) { | 593 | if (handle_signal(signr, &info, &ka, oldset, regs, in_syscall)) { |
| 594 | DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", | 594 | DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", |
| 595 | regs->gr[28]); | 595 | regs->gr[28]); |
| 596 | return 1; | 596 | return 1; |
| 597 | } | 597 | } |
| 598 | } | 598 | } |
| 599 | /* end of while(1) looping forever if we can't force a signal */ | 599 | /* end of while(1) looping forever if we can't force a signal */ |
| 600 | 600 | ||
| 601 | /* Did we come from a system call? */ | 601 | /* Did we come from a system call? */ |
| 602 | if (in_syscall) { | 602 | if (in_syscall) { |
| 603 | /* Restart the system call - no handlers present */ | 603 | /* Restart the system call - no handlers present */ |
| 604 | if (regs->gr[28] == -ERESTART_RESTARTBLOCK) { | 604 | if (regs->gr[28] == -ERESTART_RESTARTBLOCK) { |
| 605 | unsigned int *usp = (unsigned int *)regs->gr[30]; | 605 | unsigned int *usp = (unsigned int *)regs->gr[30]; |
| 606 | 606 | ||
| 607 | /* Setup a trampoline to restart the syscall | 607 | /* Setup a trampoline to restart the syscall |
| 608 | * with __NR_restart_syscall | 608 | * with __NR_restart_syscall |
| 609 | * | 609 | * |
| 610 | * 0: <return address (orig r31)> | 610 | * 0: <return address (orig r31)> |
| 611 | * 4: <2nd half for 64-bit> | 611 | * 4: <2nd half for 64-bit> |
| 612 | * 8: ldw 0(%sp), %r31 | 612 | * 8: ldw 0(%sp), %r31 |
| 613 | * 12: be 0x100(%sr2, %r0) | 613 | * 12: be 0x100(%sr2, %r0) |
| 614 | * 16: ldi __NR_restart_syscall, %r20 | 614 | * 16: ldi __NR_restart_syscall, %r20 |
| 615 | */ | 615 | */ |
| 616 | #ifndef __LP64__ | 616 | #ifndef __LP64__ |
| 617 | put_user(regs->gr[31], &usp[0]); | 617 | put_user(regs->gr[31], &usp[0]); |
| 618 | put_user(0x0fc0109f, &usp[2]); | 618 | put_user(0x0fc0109f, &usp[2]); |
| 619 | #else | 619 | #else |
| 620 | put_user(regs->gr[31] >> 32, &usp[0]); | 620 | put_user(regs->gr[31] >> 32, &usp[0]); |
| 621 | put_user(regs->gr[31] & 0xffffffff, &usp[1]); | 621 | put_user(regs->gr[31] & 0xffffffff, &usp[1]); |
| 622 | put_user(0x0fc010df, &usp[2]); | 622 | put_user(0x0fc010df, &usp[2]); |
| 623 | #endif | 623 | #endif |
| 624 | put_user(0xe0008200, &usp[3]); | 624 | put_user(0xe0008200, &usp[3]); |
| 625 | put_user(0x34140000, &usp[4]); | 625 | put_user(0x34140000, &usp[4]); |
| 626 | 626 | ||
| 627 | /* Stack is 64-byte aligned, and we only need | 627 | /* Stack is 64-byte aligned, and we only need |
| 628 | * to flush 1 cache line. | 628 | * to flush 1 cache line. |
| 629 | * Flushing one cacheline is cheap. | 629 | * Flushing one cacheline is cheap. |
| 630 | * "sync" on bigger (> 4 way) boxes is not. | 630 | * "sync" on bigger (> 4 way) boxes is not. |
| 631 | */ | 631 | */ |
| 632 | asm("fdc %%r0(%%sr3, %0)\n" | 632 | asm("fdc %%r0(%%sr3, %0)\n" |
| 633 | "sync\n" | 633 | "sync\n" |
| 634 | "fic %%r0(%%sr3, %0)\n" | 634 | "fic %%r0(%%sr3, %0)\n" |
| 635 | "sync\n" | 635 | "sync\n" |
| 636 | : : "r"(regs->gr[30])); | 636 | : : "r"(regs->gr[30])); |
| 637 | 637 | ||
| 638 | regs->gr[31] = regs->gr[30] + 8; | 638 | regs->gr[31] = regs->gr[30] + 8; |
| 639 | /* Preserve original r28. */ | 639 | /* Preserve original r28. */ |
| 640 | regs->gr[28] = regs->orig_r28; | 640 | regs->gr[28] = regs->orig_r28; |
| 641 | } else if (regs->gr[28] == -ERESTARTNOHAND || | 641 | } else if (regs->gr[28] == -ERESTARTNOHAND || |
| 642 | regs->gr[28] == -ERESTARTSYS || | 642 | regs->gr[28] == -ERESTARTSYS || |
| 643 | regs->gr[28] == -ERESTARTNOINTR) { | 643 | regs->gr[28] == -ERESTARTNOINTR) { |
| 644 | /* Hooray for delayed branching. We don't | 644 | /* Hooray for delayed branching. We don't |
| 645 | have to restore %r20 (the system call | 645 | have to restore %r20 (the system call |
| 646 | number) because it gets loaded in the delay | 646 | number) because it gets loaded in the delay |
| 647 | slot of the branch external instruction. */ | 647 | slot of the branch external instruction. */ |
| 648 | regs->gr[31] -= 8; | 648 | regs->gr[31] -= 8; |
| 649 | /* Preserve original r28. */ | 649 | /* Preserve original r28. */ |
| 650 | regs->gr[28] = regs->orig_r28; | 650 | regs->gr[28] = regs->orig_r28; |
| 651 | } | 651 | } |
| 652 | } | 652 | } |
| 653 | 653 | ||
| 654 | DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", | 654 | DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", |
| 655 | regs->gr[28]); | 655 | regs->gr[28]); |
| 656 | 656 | ||
| 657 | return 0; | 657 | return 0; |
| 658 | } | 658 | } |
| 659 | 659 |
arch/sh64/kernel/signal.c
| 1 | /* | 1 | /* |
| 2 | * This file is subject to the terms and conditions of the GNU General Public | 2 | * This file is subject to the terms and conditions of the GNU General Public |
| 3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
| 4 | * for more details. | 4 | * for more details. |
| 5 | * | 5 | * |
| 6 | * arch/sh64/kernel/signal.c | 6 | * arch/sh64/kernel/signal.c |
| 7 | * | 7 | * |
| 8 | * Copyright (C) 2000, 2001 Paolo Alberelli | 8 | * Copyright (C) 2000, 2001 Paolo Alberelli |
| 9 | * Copyright (C) 2003 Paul Mundt | 9 | * Copyright (C) 2003 Paul Mundt |
| 10 | * Copyright (C) 2004 Richard Curnow | 10 | * Copyright (C) 2004 Richard Curnow |
| 11 | * | 11 | * |
| 12 | * Started from sh version. | 12 | * Started from sh version. |
| 13 | * | 13 | * |
| 14 | */ | 14 | */ |
| 15 | #include <linux/rwsem.h> | 15 | #include <linux/rwsem.h> |
| 16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
| 17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
| 18 | #include <linux/smp.h> | 18 | #include <linux/smp.h> |
| 19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
| 20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 21 | #include <linux/signal.h> | 21 | #include <linux/signal.h> |
| 22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
| 23 | #include <linux/wait.h> | 23 | #include <linux/wait.h> |
| 24 | #include <linux/personality.h> | 24 | #include <linux/personality.h> |
| 25 | #include <linux/suspend.h> | 25 | #include <linux/suspend.h> |
| 26 | #include <linux/ptrace.h> | 26 | #include <linux/ptrace.h> |
| 27 | #include <linux/unistd.h> | 27 | #include <linux/unistd.h> |
| 28 | #include <linux/stddef.h> | 28 | #include <linux/stddef.h> |
| 29 | #include <linux/personality.h> | 29 | #include <linux/personality.h> |
| 30 | #include <asm/ucontext.h> | 30 | #include <asm/ucontext.h> |
| 31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
| 32 | #include <asm/pgtable.h> | 32 | #include <asm/pgtable.h> |
| 33 | 33 | ||
| 34 | 34 | ||
| 35 | #define REG_RET 9 | 35 | #define REG_RET 9 |
| 36 | #define REG_ARG1 2 | 36 | #define REG_ARG1 2 |
| 37 | #define REG_ARG2 3 | 37 | #define REG_ARG2 3 |
| 38 | #define REG_ARG3 4 | 38 | #define REG_ARG3 4 |
| 39 | #define REG_SP 15 | 39 | #define REG_SP 15 |
| 40 | #define REG_PR 18 | 40 | #define REG_PR 18 |
| 41 | #define REF_REG_RET regs->regs[REG_RET] | 41 | #define REF_REG_RET regs->regs[REG_RET] |
| 42 | #define REF_REG_SP regs->regs[REG_SP] | 42 | #define REF_REG_SP regs->regs[REG_SP] |
| 43 | #define DEREF_REG_PR regs->regs[REG_PR] | 43 | #define DEREF_REG_PR regs->regs[REG_PR] |
| 44 | 44 | ||
| 45 | #define DEBUG_SIG 0 | 45 | #define DEBUG_SIG 0 |
| 46 | 46 | ||
| 47 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 47 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 48 | 48 | ||
| 49 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | 49 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); |
| 50 | 50 | ||
| 51 | /* | 51 | /* |
| 52 | * Atomically swap in the new signal mask, and wait for a signal. | 52 | * Atomically swap in the new signal mask, and wait for a signal. |
| 53 | */ | 53 | */ |
| 54 | 54 | ||
| 55 | asmlinkage int | 55 | asmlinkage int |
| 56 | sys_sigsuspend(old_sigset_t mask, | 56 | sys_sigsuspend(old_sigset_t mask, |
| 57 | unsigned long r3, unsigned long r4, unsigned long r5, | 57 | unsigned long r3, unsigned long r4, unsigned long r5, |
| 58 | unsigned long r6, unsigned long r7, | 58 | unsigned long r6, unsigned long r7, |
| 59 | struct pt_regs * regs) | 59 | struct pt_regs * regs) |
| 60 | { | 60 | { |
| 61 | sigset_t saveset; | 61 | sigset_t saveset; |
| 62 | 62 | ||
| 63 | mask &= _BLOCKABLE; | 63 | mask &= _BLOCKABLE; |
| 64 | spin_lock_irq(¤t->sighand->siglock); | 64 | spin_lock_irq(¤t->sighand->siglock); |
| 65 | saveset = current->blocked; | 65 | saveset = current->blocked; |
| 66 | siginitset(¤t->blocked, mask); | 66 | siginitset(¤t->blocked, mask); |
| 67 | recalc_sigpending(); | 67 | recalc_sigpending(); |
| 68 | spin_unlock_irq(¤t->sighand->siglock); | 68 | spin_unlock_irq(¤t->sighand->siglock); |
| 69 | 69 | ||
| 70 | REF_REG_RET = -EINTR; | 70 | REF_REG_RET = -EINTR; |
| 71 | while (1) { | 71 | while (1) { |
| 72 | current->state = TASK_INTERRUPTIBLE; | 72 | current->state = TASK_INTERRUPTIBLE; |
| 73 | schedule(); | 73 | schedule(); |
| 74 | regs->pc += 4; /* because sys_sigreturn decrements the pc */ | 74 | regs->pc += 4; /* because sys_sigreturn decrements the pc */ |
| 75 | if (do_signal(regs, &saveset)) { | 75 | if (do_signal(regs, &saveset)) { |
| 76 | /* pc now points at signal handler. Need to decrement | 76 | /* pc now points at signal handler. Need to decrement |
| 77 | it because entry.S will increment it. */ | 77 | it because entry.S will increment it. */ |
| 78 | regs->pc -= 4; | 78 | regs->pc -= 4; |
| 79 | return -EINTR; | 79 | return -EINTR; |
| 80 | } | 80 | } |
| 81 | } | 81 | } |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | asmlinkage int | 84 | asmlinkage int |
| 85 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, | 85 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, |
| 86 | unsigned long r4, unsigned long r5, unsigned long r6, | 86 | unsigned long r4, unsigned long r5, unsigned long r6, |
| 87 | unsigned long r7, | 87 | unsigned long r7, |
| 88 | struct pt_regs * regs) | 88 | struct pt_regs * regs) |
| 89 | { | 89 | { |
| 90 | sigset_t saveset, newset; | 90 | sigset_t saveset, newset; |
| 91 | 91 | ||
| 92 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 92 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
| 93 | if (sigsetsize != sizeof(sigset_t)) | 93 | if (sigsetsize != sizeof(sigset_t)) |
| 94 | return -EINVAL; | 94 | return -EINVAL; |
| 95 | 95 | ||
| 96 | if (copy_from_user(&newset, unewset, sizeof(newset))) | 96 | if (copy_from_user(&newset, unewset, sizeof(newset))) |
| 97 | return -EFAULT; | 97 | return -EFAULT; |
| 98 | sigdelsetmask(&newset, ~_BLOCKABLE); | 98 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 99 | spin_lock_irq(¤t->sighand->siglock); | 99 | spin_lock_irq(¤t->sighand->siglock); |
| 100 | saveset = current->blocked; | 100 | saveset = current->blocked; |
| 101 | current->blocked = newset; | 101 | current->blocked = newset; |
| 102 | recalc_sigpending(); | 102 | recalc_sigpending(); |
| 103 | spin_unlock_irq(¤t->sighand->siglock); | 103 | spin_unlock_irq(¤t->sighand->siglock); |
| 104 | 104 | ||
| 105 | REF_REG_RET = -EINTR; | 105 | REF_REG_RET = -EINTR; |
| 106 | while (1) { | 106 | while (1) { |
| 107 | current->state = TASK_INTERRUPTIBLE; | 107 | current->state = TASK_INTERRUPTIBLE; |
| 108 | schedule(); | 108 | schedule(); |
| 109 | regs->pc += 4; /* because sys_sigreturn decrements the pc */ | 109 | regs->pc += 4; /* because sys_sigreturn decrements the pc */ |
| 110 | if (do_signal(regs, &saveset)) { | 110 | if (do_signal(regs, &saveset)) { |
| 111 | /* pc now points at signal handler. Need to decrement | 111 | /* pc now points at signal handler. Need to decrement |
| 112 | it because entry.S will increment it. */ | 112 | it because entry.S will increment it. */ |
| 113 | regs->pc -= 4; | 113 | regs->pc -= 4; |
| 114 | return -EINTR; | 114 | return -EINTR; |
| 115 | } | 115 | } |
| 116 | } | 116 | } |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | asmlinkage int | 119 | asmlinkage int |
| 120 | sys_sigaction(int sig, const struct old_sigaction __user *act, | 120 | sys_sigaction(int sig, const struct old_sigaction __user *act, |
| 121 | struct old_sigaction __user *oact) | 121 | struct old_sigaction __user *oact) |
| 122 | { | 122 | { |
| 123 | struct k_sigaction new_ka, old_ka; | 123 | struct k_sigaction new_ka, old_ka; |
| 124 | int ret; | 124 | int ret; |
| 125 | 125 | ||
| 126 | if (act) { | 126 | if (act) { |
| 127 | old_sigset_t mask; | 127 | old_sigset_t mask; |
| 128 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 128 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
| 129 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 129 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
| 130 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 130 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) |
| 131 | return -EFAULT; | 131 | return -EFAULT; |
| 132 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | 132 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); |
| 133 | __get_user(mask, &act->sa_mask); | 133 | __get_user(mask, &act->sa_mask); |
| 134 | siginitset(&new_ka.sa.sa_mask, mask); | 134 | siginitset(&new_ka.sa.sa_mask, mask); |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 137 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
| 138 | 138 | ||
| 139 | if (!ret && oact) { | 139 | if (!ret && oact) { |
| 140 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 140 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
| 141 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 141 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
| 142 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 142 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) |
| 143 | return -EFAULT; | 143 | return -EFAULT; |
| 144 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | 144 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
| 145 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | 145 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | return ret; | 148 | return ret; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | asmlinkage int | 151 | asmlinkage int |
| 152 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 152 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
| 153 | unsigned long r4, unsigned long r5, unsigned long r6, | 153 | unsigned long r4, unsigned long r5, unsigned long r6, |
| 154 | unsigned long r7, | 154 | unsigned long r7, |
| 155 | struct pt_regs * regs) | 155 | struct pt_regs * regs) |
| 156 | { | 156 | { |
| 157 | return do_sigaltstack(uss, uoss, REF_REG_SP); | 157 | return do_sigaltstack(uss, uoss, REF_REG_SP); |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | 160 | ||
| 161 | /* | 161 | /* |
| 162 | * Do a signal return; undo the signal stack. | 162 | * Do a signal return; undo the signal stack. |
| 163 | */ | 163 | */ |
| 164 | 164 | ||
| 165 | struct sigframe | 165 | struct sigframe |
| 166 | { | 166 | { |
| 167 | struct sigcontext sc; | 167 | struct sigcontext sc; |
| 168 | unsigned long extramask[_NSIG_WORDS-1]; | 168 | unsigned long extramask[_NSIG_WORDS-1]; |
| 169 | long long retcode[2]; | 169 | long long retcode[2]; |
| 170 | }; | 170 | }; |
| 171 | 171 | ||
| 172 | struct rt_sigframe | 172 | struct rt_sigframe |
| 173 | { | 173 | { |
| 174 | struct siginfo __user *pinfo; | 174 | struct siginfo __user *pinfo; |
| 175 | void *puc; | 175 | void *puc; |
| 176 | struct siginfo info; | 176 | struct siginfo info; |
| 177 | struct ucontext uc; | 177 | struct ucontext uc; |
| 178 | long long retcode[2]; | 178 | long long retcode[2]; |
| 179 | }; | 179 | }; |
| 180 | 180 | ||
| 181 | #ifdef CONFIG_SH_FPU | 181 | #ifdef CONFIG_SH_FPU |
| 182 | static inline int | 182 | static inline int |
| 183 | restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) | 183 | restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) |
| 184 | { | 184 | { |
| 185 | int err = 0; | 185 | int err = 0; |
| 186 | int fpvalid; | 186 | int fpvalid; |
| 187 | 187 | ||
| 188 | err |= __get_user (fpvalid, &sc->sc_fpvalid); | 188 | err |= __get_user (fpvalid, &sc->sc_fpvalid); |
| 189 | conditional_used_math(fpvalid); | 189 | conditional_used_math(fpvalid); |
| 190 | if (! fpvalid) | 190 | if (! fpvalid) |
| 191 | return err; | 191 | return err; |
| 192 | 192 | ||
| 193 | if (current == last_task_used_math) { | 193 | if (current == last_task_used_math) { |
| 194 | last_task_used_math = NULL; | 194 | last_task_used_math = NULL; |
| 195 | regs->sr |= SR_FD; | 195 | regs->sr |= SR_FD; |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | err |= __copy_from_user(¤t->thread.fpu.hard, &sc->sc_fpregs[0], | 198 | err |= __copy_from_user(¤t->thread.fpu.hard, &sc->sc_fpregs[0], |
| 199 | (sizeof(long long) * 32) + (sizeof(int) * 1)); | 199 | (sizeof(long long) * 32) + (sizeof(int) * 1)); |
| 200 | 200 | ||
| 201 | return err; | 201 | return err; |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | static inline int | 204 | static inline int |
| 205 | setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) | 205 | setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) |
| 206 | { | 206 | { |
| 207 | int err = 0; | 207 | int err = 0; |
| 208 | int fpvalid; | 208 | int fpvalid; |
| 209 | 209 | ||
| 210 | fpvalid = !!used_math(); | 210 | fpvalid = !!used_math(); |
| 211 | err |= __put_user(fpvalid, &sc->sc_fpvalid); | 211 | err |= __put_user(fpvalid, &sc->sc_fpvalid); |
| 212 | if (! fpvalid) | 212 | if (! fpvalid) |
| 213 | return err; | 213 | return err; |
| 214 | 214 | ||
| 215 | if (current == last_task_used_math) { | 215 | if (current == last_task_used_math) { |
| 216 | grab_fpu(); | 216 | grab_fpu(); |
| 217 | fpsave(¤t->thread.fpu.hard); | 217 | fpsave(¤t->thread.fpu.hard); |
| 218 | release_fpu(); | 218 | release_fpu(); |
| 219 | last_task_used_math = NULL; | 219 | last_task_used_math = NULL; |
| 220 | regs->sr |= SR_FD; | 220 | regs->sr |= SR_FD; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | err |= __copy_to_user(&sc->sc_fpregs[0], ¤t->thread.fpu.hard, | 223 | err |= __copy_to_user(&sc->sc_fpregs[0], ¤t->thread.fpu.hard, |
| 224 | (sizeof(long long) * 32) + (sizeof(int) * 1)); | 224 | (sizeof(long long) * 32) + (sizeof(int) * 1)); |
| 225 | clear_used_math(); | 225 | clear_used_math(); |
| 226 | 226 | ||
| 227 | return err; | 227 | return err; |
| 228 | } | 228 | } |
| 229 | #else | 229 | #else |
| 230 | static inline int | 230 | static inline int |
| 231 | restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) | 231 | restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) |
| 232 | {} | 232 | {} |
| 233 | static inline int | 233 | static inline int |
| 234 | setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) | 234 | setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc) |
| 235 | {} | 235 | {} |
| 236 | #endif | 236 | #endif |
| 237 | 237 | ||
| 238 | static int | 238 | static int |
| 239 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p) | 239 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p) |
| 240 | { | 240 | { |
| 241 | unsigned int err = 0; | 241 | unsigned int err = 0; |
| 242 | unsigned long long current_sr, new_sr; | 242 | unsigned long long current_sr, new_sr; |
| 243 | #define SR_MASK 0xffff8cfd | 243 | #define SR_MASK 0xffff8cfd |
| 244 | 244 | ||
| 245 | #define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) | 245 | #define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) |
| 246 | 246 | ||
| 247 | COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]); | 247 | COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]); |
| 248 | COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]); | 248 | COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]); |
| 249 | COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]); | 249 | COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]); |
| 250 | COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]); | 250 | COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]); |
| 251 | COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]); | 251 | COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]); |
| 252 | COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]); | 252 | COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]); |
| 253 | COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]); | 253 | COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]); |
| 254 | COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]); | 254 | COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]); |
| 255 | COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]); | 255 | COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]); |
| 256 | COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]); | 256 | COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]); |
| 257 | COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]); | 257 | COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]); |
| 258 | COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]); | 258 | COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]); |
| 259 | COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]); | 259 | COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]); |
| 260 | COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]); | 260 | COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]); |
| 261 | COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]); | 261 | COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]); |
| 262 | COPY(regs[60]); COPY(regs[61]); COPY(regs[62]); | 262 | COPY(regs[60]); COPY(regs[61]); COPY(regs[62]); |
| 263 | COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]); | 263 | COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]); |
| 264 | COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]); | 264 | COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]); |
| 265 | 265 | ||
| 266 | /* Prevent the signal handler manipulating SR in a way that can | 266 | /* Prevent the signal handler manipulating SR in a way that can |
| 267 | crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be | 267 | crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be |
| 268 | modified */ | 268 | modified */ |
| 269 | current_sr = regs->sr; | 269 | current_sr = regs->sr; |
| 270 | err |= __get_user(new_sr, &sc->sc_sr); | 270 | err |= __get_user(new_sr, &sc->sc_sr); |
| 271 | regs->sr &= SR_MASK; | 271 | regs->sr &= SR_MASK; |
| 272 | regs->sr |= (new_sr & ~SR_MASK); | 272 | regs->sr |= (new_sr & ~SR_MASK); |
| 273 | 273 | ||
| 274 | COPY(pc); | 274 | COPY(pc); |
| 275 | 275 | ||
| 276 | #undef COPY | 276 | #undef COPY |
| 277 | 277 | ||
| 278 | /* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr | 278 | /* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr |
| 279 | * has been restored above.) */ | 279 | * has been restored above.) */ |
| 280 | err |= restore_sigcontext_fpu(regs, sc); | 280 | err |= restore_sigcontext_fpu(regs, sc); |
| 281 | 281 | ||
| 282 | regs->syscall_nr = -1; /* disable syscall checks */ | 282 | regs->syscall_nr = -1; /* disable syscall checks */ |
| 283 | err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]); | 283 | err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]); |
| 284 | return err; | 284 | return err; |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3, | 287 | asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3, |
| 288 | unsigned long r4, unsigned long r5, | 288 | unsigned long r4, unsigned long r5, |
| 289 | unsigned long r6, unsigned long r7, | 289 | unsigned long r6, unsigned long r7, |
| 290 | struct pt_regs * regs) | 290 | struct pt_regs * regs) |
| 291 | { | 291 | { |
| 292 | struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP; | 292 | struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP; |
| 293 | sigset_t set; | 293 | sigset_t set; |
| 294 | long long ret; | 294 | long long ret; |
| 295 | 295 | ||
| 296 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 296 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 297 | goto badframe; | 297 | goto badframe; |
| 298 | 298 | ||
| 299 | if (__get_user(set.sig[0], &frame->sc.oldmask) | 299 | if (__get_user(set.sig[0], &frame->sc.oldmask) |
| 300 | || (_NSIG_WORDS > 1 | 300 | || (_NSIG_WORDS > 1 |
| 301 | && __copy_from_user(&set.sig[1], &frame->extramask, | 301 | && __copy_from_user(&set.sig[1], &frame->extramask, |
| 302 | sizeof(frame->extramask)))) | 302 | sizeof(frame->extramask)))) |
| 303 | goto badframe; | 303 | goto badframe; |
| 304 | 304 | ||
| 305 | sigdelsetmask(&set, ~_BLOCKABLE); | 305 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 306 | 306 | ||
| 307 | spin_lock_irq(¤t->sighand->siglock); | 307 | spin_lock_irq(¤t->sighand->siglock); |
| 308 | current->blocked = set; | 308 | current->blocked = set; |
| 309 | recalc_sigpending(); | 309 | recalc_sigpending(); |
| 310 | spin_unlock_irq(¤t->sighand->siglock); | 310 | spin_unlock_irq(¤t->sighand->siglock); |
| 311 | 311 | ||
| 312 | if (restore_sigcontext(regs, &frame->sc, &ret)) | 312 | if (restore_sigcontext(regs, &frame->sc, &ret)) |
| 313 | goto badframe; | 313 | goto badframe; |
| 314 | regs->pc -= 4; | 314 | regs->pc -= 4; |
| 315 | 315 | ||
| 316 | return (int) ret; | 316 | return (int) ret; |
| 317 | 317 | ||
| 318 | badframe: | 318 | badframe: |
| 319 | force_sig(SIGSEGV, current); | 319 | force_sig(SIGSEGV, current); |
| 320 | return 0; | 320 | return 0; |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3, | 323 | asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3, |
| 324 | unsigned long r4, unsigned long r5, | 324 | unsigned long r4, unsigned long r5, |
| 325 | unsigned long r6, unsigned long r7, | 325 | unsigned long r6, unsigned long r7, |
| 326 | struct pt_regs * regs) | 326 | struct pt_regs * regs) |
| 327 | { | 327 | { |
| 328 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP; | 328 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP; |
| 329 | sigset_t set; | 329 | sigset_t set; |
| 330 | stack_t __user st; | 330 | stack_t __user st; |
| 331 | long long ret; | 331 | long long ret; |
| 332 | 332 | ||
| 333 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 333 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 334 | goto badframe; | 334 | goto badframe; |
| 335 | 335 | ||
| 336 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 336 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| 337 | goto badframe; | 337 | goto badframe; |
| 338 | 338 | ||
| 339 | sigdelsetmask(&set, ~_BLOCKABLE); | 339 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 340 | spin_lock_irq(¤t->sighand->siglock); | 340 | spin_lock_irq(¤t->sighand->siglock); |
| 341 | current->blocked = set; | 341 | current->blocked = set; |
| 342 | recalc_sigpending(); | 342 | recalc_sigpending(); |
| 343 | spin_unlock_irq(¤t->sighand->siglock); | 343 | spin_unlock_irq(¤t->sighand->siglock); |
| 344 | 344 | ||
| 345 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret)) | 345 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret)) |
| 346 | goto badframe; | 346 | goto badframe; |
| 347 | regs->pc -= 4; | 347 | regs->pc -= 4; |
| 348 | 348 | ||
| 349 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) | 349 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) |
| 350 | goto badframe; | 350 | goto badframe; |
| 351 | /* It is more difficult to avoid calling this function than to | 351 | /* It is more difficult to avoid calling this function than to |
| 352 | call it and ignore errors. */ | 352 | call it and ignore errors. */ |
| 353 | do_sigaltstack(&st, NULL, REF_REG_SP); | 353 | do_sigaltstack(&st, NULL, REF_REG_SP); |
| 354 | 354 | ||
| 355 | return (int) ret; | 355 | return (int) ret; |
| 356 | 356 | ||
| 357 | badframe: | 357 | badframe: |
| 358 | force_sig(SIGSEGV, current); | 358 | force_sig(SIGSEGV, current); |
| 359 | return 0; | 359 | return 0; |
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | /* | 362 | /* |
| 363 | * Set up a signal frame. | 363 | * Set up a signal frame. |
| 364 | */ | 364 | */ |
| 365 | 365 | ||
| 366 | static int | 366 | static int |
| 367 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | 367 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
| 368 | unsigned long mask) | 368 | unsigned long mask) |
| 369 | { | 369 | { |
| 370 | int err = 0; | 370 | int err = 0; |
| 371 | 371 | ||
| 372 | /* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */ | 372 | /* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */ |
| 373 | err |= setup_sigcontext_fpu(regs, sc); | 373 | err |= setup_sigcontext_fpu(regs, sc); |
| 374 | 374 | ||
| 375 | #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) | 375 | #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) |
| 376 | 376 | ||
| 377 | COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]); | 377 | COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]); |
| 378 | COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]); | 378 | COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]); |
| 379 | COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]); | 379 | COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]); |
| 380 | COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]); | 380 | COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]); |
| 381 | COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]); | 381 | COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]); |
| 382 | COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]); | 382 | COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]); |
| 383 | COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]); | 383 | COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]); |
| 384 | COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]); | 384 | COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]); |
| 385 | COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]); | 385 | COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]); |
| 386 | COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]); | 386 | COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]); |
| 387 | COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]); | 387 | COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]); |
| 388 | COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]); | 388 | COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]); |
| 389 | COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]); | 389 | COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]); |
| 390 | COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]); | 390 | COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]); |
| 391 | COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]); | 391 | COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]); |
| 392 | COPY(regs[60]); COPY(regs[61]); COPY(regs[62]); | 392 | COPY(regs[60]); COPY(regs[61]); COPY(regs[62]); |
| 393 | COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]); | 393 | COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]); |
| 394 | COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]); | 394 | COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]); |
| 395 | COPY(sr); COPY(pc); | 395 | COPY(sr); COPY(pc); |
| 396 | 396 | ||
| 397 | #undef COPY | 397 | #undef COPY |
| 398 | 398 | ||
| 399 | err |= __put_user(mask, &sc->oldmask); | 399 | err |= __put_user(mask, &sc->oldmask); |
| 400 | 400 | ||
| 401 | return err; | 401 | return err; |
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | /* | 404 | /* |
| 405 | * Determine which stack to use.. | 405 | * Determine which stack to use.. |
| 406 | */ | 406 | */ |
| 407 | static inline void __user * | 407 | static inline void __user * |
| 408 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | 408 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) |
| 409 | { | 409 | { |
| 410 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) | 410 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) |
| 411 | sp = current->sas_ss_sp + current->sas_ss_size; | 411 | sp = current->sas_ss_sp + current->sas_ss_size; |
| 412 | 412 | ||
| 413 | return (void __user *)((sp - frame_size) & -8ul); | 413 | return (void __user *)((sp - frame_size) & -8ul); |
| 414 | } | 414 | } |
| 415 | 415 | ||
| 416 | void sa_default_restorer(void); /* See comments below */ | 416 | void sa_default_restorer(void); /* See comments below */ |
| 417 | void sa_default_rt_restorer(void); /* See comments below */ | 417 | void sa_default_rt_restorer(void); /* See comments below */ |
| 418 | 418 | ||
| 419 | static void setup_frame(int sig, struct k_sigaction *ka, | 419 | static void setup_frame(int sig, struct k_sigaction *ka, |
| 420 | sigset_t *set, struct pt_regs *regs) | 420 | sigset_t *set, struct pt_regs *regs) |
| 421 | { | 421 | { |
| 422 | struct sigframe __user *frame; | 422 | struct sigframe __user *frame; |
| 423 | int err = 0; | 423 | int err = 0; |
| 424 | int signal; | 424 | int signal; |
| 425 | 425 | ||
| 426 | frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame)); | 426 | frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame)); |
| 427 | 427 | ||
| 428 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 428 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 429 | goto give_sigsegv; | 429 | goto give_sigsegv; |
| 430 | 430 | ||
| 431 | signal = current_thread_info()->exec_domain | 431 | signal = current_thread_info()->exec_domain |
| 432 | && current_thread_info()->exec_domain->signal_invmap | 432 | && current_thread_info()->exec_domain->signal_invmap |
| 433 | && sig < 32 | 433 | && sig < 32 |
| 434 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 434 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 435 | : sig; | 435 | : sig; |
| 436 | 436 | ||
| 437 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); | 437 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); |
| 438 | 438 | ||
| 439 | /* Give up earlier as i386, in case */ | 439 | /* Give up earlier as i386, in case */ |
| 440 | if (err) | 440 | if (err) |
| 441 | goto give_sigsegv; | 441 | goto give_sigsegv; |
| 442 | 442 | ||
| 443 | if (_NSIG_WORDS > 1) { | 443 | if (_NSIG_WORDS > 1) { |
| 444 | err |= __copy_to_user(frame->extramask, &set->sig[1], | 444 | err |= __copy_to_user(frame->extramask, &set->sig[1], |
| 445 | sizeof(frame->extramask)); } | 445 | sizeof(frame->extramask)); } |
| 446 | 446 | ||
| 447 | /* Give up earlier as i386, in case */ | 447 | /* Give up earlier as i386, in case */ |
| 448 | if (err) | 448 | if (err) |
| 449 | goto give_sigsegv; | 449 | goto give_sigsegv; |
| 450 | 450 | ||
| 451 | /* Set up to return from userspace. If provided, use a stub | 451 | /* Set up to return from userspace. If provided, use a stub |
| 452 | already in userspace. */ | 452 | already in userspace. */ |
| 453 | if (ka->sa.sa_flags & SA_RESTORER) { | 453 | if (ka->sa.sa_flags & SA_RESTORER) { |
| 454 | DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; | 454 | DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; |
| 455 | 455 | ||
| 456 | /* | 456 | /* |
| 457 | * On SH5 all edited pointers are subject to NEFF | 457 | * On SH5 all edited pointers are subject to NEFF |
| 458 | */ | 458 | */ |
| 459 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? | 459 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? |
| 460 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; | 460 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; |
| 461 | } else { | 461 | } else { |
| 462 | /* | 462 | /* |
| 463 | * Different approach on SH5. | 463 | * Different approach on SH5. |
| 464 | * . Endianness independent asm code gets placed in entry.S . | 464 | * . Endianness independent asm code gets placed in entry.S . |
| 465 | * This is limited to four ASM instructions corresponding | 465 | * This is limited to four ASM instructions corresponding |
| 466 | * to two long longs in size. | 466 | * to two long longs in size. |
| 467 | * . err checking is done on the else branch only | 467 | * . err checking is done on the else branch only |
| 468 | * . flush_icache_range() is called upon __put_user() only | 468 | * . flush_icache_range() is called upon __put_user() only |
| 469 | * . all edited pointers are subject to NEFF | 469 | * . all edited pointers are subject to NEFF |
| 470 | * . being code, linker turns ShMedia bit on, always | 470 | * . being code, linker turns ShMedia bit on, always |
| 471 | * dereference index -1. | 471 | * dereference index -1. |
| 472 | */ | 472 | */ |
| 473 | DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; | 473 | DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; |
| 474 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? | 474 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? |
| 475 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; | 475 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; |
| 476 | 476 | ||
| 477 | if (__copy_to_user(frame->retcode, | 477 | if (__copy_to_user(frame->retcode, |
| 478 | (unsigned long long)sa_default_restorer & (~1), 16) != 0) | 478 | (unsigned long long)sa_default_restorer & (~1), 16) != 0) |
| 479 | goto give_sigsegv; | 479 | goto give_sigsegv; |
| 480 | 480 | ||
| 481 | /* Cohere the trampoline with the I-cache. */ | 481 | /* Cohere the trampoline with the I-cache. */ |
| 482 | flush_cache_sigtramp(DEREF_REG_PR-1, DEREF_REG_PR-1+16); | 482 | flush_cache_sigtramp(DEREF_REG_PR-1, DEREF_REG_PR-1+16); |
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | /* | 485 | /* |
| 486 | * Set up registers for signal handler. | 486 | * Set up registers for signal handler. |
| 487 | * All edited pointers are subject to NEFF. | 487 | * All edited pointers are subject to NEFF. |
| 488 | */ | 488 | */ |
| 489 | regs->regs[REG_SP] = (unsigned long) frame; | 489 | regs->regs[REG_SP] = (unsigned long) frame; |
| 490 | regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? | 490 | regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? |
| 491 | (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; | 491 | (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; |
| 492 | regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ | 492 | regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ |
| 493 | 493 | ||
| 494 | /* FIXME: | 494 | /* FIXME: |
| 495 | The glibc profiling support for SH-5 needs to be passed a sigcontext | 495 | The glibc profiling support for SH-5 needs to be passed a sigcontext |
| 496 | so it can retrieve the PC. At some point during 2003 the glibc | 496 | so it can retrieve the PC. At some point during 2003 the glibc |
| 497 | support was changed to receive the sigcontext through the 2nd | 497 | support was changed to receive the sigcontext through the 2nd |
| 498 | argument, but there are still versions of libc.so in use that use | 498 | argument, but there are still versions of libc.so in use that use |
| 499 | the 3rd argument. Until libc.so is stabilised, pass the sigcontext | 499 | the 3rd argument. Until libc.so is stabilised, pass the sigcontext |
| 500 | through both 2nd and 3rd arguments. | 500 | through both 2nd and 3rd arguments. |
| 501 | */ | 501 | */ |
| 502 | 502 | ||
| 503 | regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc; | 503 | regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc; |
| 504 | regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc; | 504 | regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc; |
| 505 | 505 | ||
| 506 | regs->pc = (unsigned long) ka->sa.sa_handler; | 506 | regs->pc = (unsigned long) ka->sa.sa_handler; |
| 507 | regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; | 507 | regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; |
| 508 | 508 | ||
| 509 | set_fs(USER_DS); | 509 | set_fs(USER_DS); |
| 510 | 510 | ||
| 511 | #if DEBUG_SIG | 511 | #if DEBUG_SIG |
| 512 | /* Broken %016Lx */ | 512 | /* Broken %016Lx */ |
| 513 | printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", | 513 | printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", |
| 514 | signal, | 514 | signal, |
| 515 | current->comm, current->pid, frame, | 515 | current->comm, current->pid, frame, |
| 516 | regs->pc >> 32, regs->pc & 0xffffffff, | 516 | regs->pc >> 32, regs->pc & 0xffffffff, |
| 517 | DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); | 517 | DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); |
| 518 | #endif | 518 | #endif |
| 519 | 519 | ||
| 520 | return; | 520 | return; |
| 521 | 521 | ||
| 522 | give_sigsegv: | 522 | give_sigsegv: |
| 523 | force_sigsegv(sig, current); | 523 | force_sigsegv(sig, current); |
| 524 | } | 524 | } |
| 525 | 525 | ||
| 526 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 526 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 527 | sigset_t *set, struct pt_regs *regs) | 527 | sigset_t *set, struct pt_regs *regs) |
| 528 | { | 528 | { |
| 529 | struct rt_sigframe __user *frame; | 529 | struct rt_sigframe __user *frame; |
| 530 | int err = 0; | 530 | int err = 0; |
| 531 | int signal; | 531 | int signal; |
| 532 | 532 | ||
| 533 | frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame)); | 533 | frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame)); |
| 534 | 534 | ||
| 535 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 535 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 536 | goto give_sigsegv; | 536 | goto give_sigsegv; |
| 537 | 537 | ||
| 538 | signal = current_thread_info()->exec_domain | 538 | signal = current_thread_info()->exec_domain |
| 539 | && current_thread_info()->exec_domain->signal_invmap | 539 | && current_thread_info()->exec_domain->signal_invmap |
| 540 | && sig < 32 | 540 | && sig < 32 |
| 541 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 541 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 542 | : sig; | 542 | : sig; |
| 543 | 543 | ||
| 544 | err |= __put_user(&frame->info, &frame->pinfo); | 544 | err |= __put_user(&frame->info, &frame->pinfo); |
| 545 | err |= __put_user(&frame->uc, &frame->puc); | 545 | err |= __put_user(&frame->uc, &frame->puc); |
| 546 | err |= copy_siginfo_to_user(&frame->info, info); | 546 | err |= copy_siginfo_to_user(&frame->info, info); |
| 547 | 547 | ||
| 548 | /* Give up earlier as i386, in case */ | 548 | /* Give up earlier as i386, in case */ |
| 549 | if (err) | 549 | if (err) |
| 550 | goto give_sigsegv; | 550 | goto give_sigsegv; |
| 551 | 551 | ||
| 552 | /* Create the ucontext. */ | 552 | /* Create the ucontext. */ |
| 553 | err |= __put_user(0, &frame->uc.uc_flags); | 553 | err |= __put_user(0, &frame->uc.uc_flags); |
| 554 | err |= __put_user(0, &frame->uc.uc_link); | 554 | err |= __put_user(0, &frame->uc.uc_link); |
| 555 | err |= __put_user((void *)current->sas_ss_sp, | 555 | err |= __put_user((void *)current->sas_ss_sp, |
| 556 | &frame->uc.uc_stack.ss_sp); | 556 | &frame->uc.uc_stack.ss_sp); |
| 557 | err |= __put_user(sas_ss_flags(regs->regs[REG_SP]), | 557 | err |= __put_user(sas_ss_flags(regs->regs[REG_SP]), |
| 558 | &frame->uc.uc_stack.ss_flags); | 558 | &frame->uc.uc_stack.ss_flags); |
| 559 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 559 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
| 560 | err |= setup_sigcontext(&frame->uc.uc_mcontext, | 560 | err |= setup_sigcontext(&frame->uc.uc_mcontext, |
| 561 | regs, set->sig[0]); | 561 | regs, set->sig[0]); |
| 562 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 562 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 563 | 563 | ||
| 564 | /* Give up earlier as i386, in case */ | 564 | /* Give up earlier as i386, in case */ |
| 565 | if (err) | 565 | if (err) |
| 566 | goto give_sigsegv; | 566 | goto give_sigsegv; |
| 567 | 567 | ||
| 568 | /* Set up to return from userspace. If provided, use a stub | 568 | /* Set up to return from userspace. If provided, use a stub |
| 569 | already in userspace. */ | 569 | already in userspace. */ |
| 570 | if (ka->sa.sa_flags & SA_RESTORER) { | 570 | if (ka->sa.sa_flags & SA_RESTORER) { |
| 571 | DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; | 571 | DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; |
| 572 | 572 | ||
| 573 | /* | 573 | /* |
| 574 | * On SH5 all edited pointers are subject to NEFF | 574 | * On SH5 all edited pointers are subject to NEFF |
| 575 | */ | 575 | */ |
| 576 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? | 576 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? |
| 577 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; | 577 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; |
| 578 | } else { | 578 | } else { |
| 579 | /* | 579 | /* |
| 580 | * Different approach on SH5. | 580 | * Different approach on SH5. |
| 581 | * . Endianness independent asm code gets placed in entry.S . | 581 | * . Endianness independent asm code gets placed in entry.S . |
| 582 | * This is limited to four ASM instructions corresponding | 582 | * This is limited to four ASM instructions corresponding |
| 583 | * to two long longs in size. | 583 | * to two long longs in size. |
| 584 | * . err checking is done on the else branch only | 584 | * . err checking is done on the else branch only |
| 585 | * . flush_icache_range() is called upon __put_user() only | 585 | * . flush_icache_range() is called upon __put_user() only |
| 586 | * . all edited pointers are subject to NEFF | 586 | * . all edited pointers are subject to NEFF |
| 587 | * . being code, linker turns ShMedia bit on, always | 587 | * . being code, linker turns ShMedia bit on, always |
| 588 | * dereference index -1. | 588 | * dereference index -1. |
| 589 | */ | 589 | */ |
| 590 | 590 | ||
| 591 | DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; | 591 | DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; |
| 592 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? | 592 | DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? |
| 593 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; | 593 | (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; |
| 594 | 594 | ||
| 595 | if (__copy_to_user(frame->retcode, | 595 | if (__copy_to_user(frame->retcode, |
| 596 | (unsigned long long)sa_default_rt_restorer & (~1), 16) != 0) | 596 | (unsigned long long)sa_default_rt_restorer & (~1), 16) != 0) |
| 597 | goto give_sigsegv; | 597 | goto give_sigsegv; |
| 598 | 598 | ||
| 599 | flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15); | 599 | flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15); |
| 600 | } | 600 | } |
| 601 | 601 | ||
| 602 | /* | 602 | /* |
| 603 | * Set up registers for signal handler. | 603 | * Set up registers for signal handler. |
| 604 | * All edited pointers are subject to NEFF. | 604 | * All edited pointers are subject to NEFF. |
| 605 | */ | 605 | */ |
| 606 | regs->regs[REG_SP] = (unsigned long) frame; | 606 | regs->regs[REG_SP] = (unsigned long) frame; |
| 607 | regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? | 607 | regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? |
| 608 | (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; | 608 | (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; |
| 609 | regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ | 609 | regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ |
| 610 | regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info; | 610 | regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info; |
| 611 | regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext; | 611 | regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext; |
| 612 | regs->pc = (unsigned long) ka->sa.sa_handler; | 612 | regs->pc = (unsigned long) ka->sa.sa_handler; |
| 613 | regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; | 613 | regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; |
| 614 | 614 | ||
| 615 | set_fs(USER_DS); | 615 | set_fs(USER_DS); |
| 616 | 616 | ||
| 617 | #if DEBUG_SIG | 617 | #if DEBUG_SIG |
| 618 | /* Broken %016Lx */ | 618 | /* Broken %016Lx */ |
| 619 | printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", | 619 | printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", |
| 620 | signal, | 620 | signal, |
| 621 | current->comm, current->pid, frame, | 621 | current->comm, current->pid, frame, |
| 622 | regs->pc >> 32, regs->pc & 0xffffffff, | 622 | regs->pc >> 32, regs->pc & 0xffffffff, |
| 623 | DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); | 623 | DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff); |
| 624 | #endif | 624 | #endif |
| 625 | 625 | ||
| 626 | return; | 626 | return; |
| 627 | 627 | ||
| 628 | give_sigsegv: | 628 | give_sigsegv: |
| 629 | force_sigsegv(sig, current); | 629 | force_sigsegv(sig, current); |
| 630 | } | 630 | } |
| 631 | 631 | ||
| 632 | /* | 632 | /* |
| 633 | * OK, we're invoking a handler | 633 | * OK, we're invoking a handler |
| 634 | */ | 634 | */ |
| 635 | 635 | ||
| 636 | static void | 636 | static void |
| 637 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 637 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
| 638 | sigset_t *oldset, struct pt_regs * regs) | 638 | sigset_t *oldset, struct pt_regs * regs) |
| 639 | { | 639 | { |
| 640 | /* Are we from a system call? */ | 640 | /* Are we from a system call? */ |
| 641 | if (regs->syscall_nr >= 0) { | 641 | if (regs->syscall_nr >= 0) { |
| 642 | /* If so, check system call restarting.. */ | 642 | /* If so, check system call restarting.. */ |
| 643 | switch (regs->regs[REG_RET]) { | 643 | switch (regs->regs[REG_RET]) { |
| 644 | case -ERESTARTNOHAND: | 644 | case -ERESTARTNOHAND: |
| 645 | regs->regs[REG_RET] = -EINTR; | 645 | regs->regs[REG_RET] = -EINTR; |
| 646 | break; | 646 | break; |
| 647 | 647 | ||
| 648 | case -ERESTARTSYS: | 648 | case -ERESTARTSYS: |
| 649 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 649 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
| 650 | regs->regs[REG_RET] = -EINTR; | 650 | regs->regs[REG_RET] = -EINTR; |
| 651 | break; | 651 | break; |
| 652 | } | 652 | } |
| 653 | /* fallthrough */ | 653 | /* fallthrough */ |
| 654 | case -ERESTARTNOINTR: | 654 | case -ERESTARTNOINTR: |
| 655 | /* Decode syscall # */ | 655 | /* Decode syscall # */ |
| 656 | regs->regs[REG_RET] = regs->syscall_nr; | 656 | regs->regs[REG_RET] = regs->syscall_nr; |
| 657 | regs->pc -= 4; | 657 | regs->pc -= 4; |
| 658 | } | 658 | } |
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | /* Set up the stack frame */ | 661 | /* Set up the stack frame */ |
| 662 | if (ka->sa.sa_flags & SA_SIGINFO) | 662 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 663 | setup_rt_frame(sig, ka, info, oldset, regs); | 663 | setup_rt_frame(sig, ka, info, oldset, regs); |
| 664 | else | 664 | else |
| 665 | setup_frame(sig, ka, oldset, regs); | 665 | setup_frame(sig, ka, oldset, regs); |
| 666 | 666 | ||
| 667 | spin_lock_irq(¤t->sighand->siglock); | 667 | spin_lock_irq(¤t->sighand->siglock); |
| 668 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 668 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
| 669 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 669 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 670 | sigaddset(¤t->blocked,sig); | 670 | sigaddset(¤t->blocked,sig); |
| 671 | recalc_sigpending(); | 671 | recalc_sigpending(); |
| 672 | spin_unlock_irq(¤t->sighand->siglock); | 672 | spin_unlock_irq(¤t->sighand->siglock); |
| 673 | } | 673 | } |
| 674 | 674 | ||
| 675 | /* | 675 | /* |
| 676 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 676 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 677 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 677 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 678 | * mistake. | 678 | * mistake. |
| 679 | * | 679 | * |
| 680 | * Note that we go through the signals twice: once to check the signals that | 680 | * Note that we go through the signals twice: once to check the signals that |
| 681 | * the kernel can handle, and then we build all the user-level signal handling | 681 | * the kernel can handle, and then we build all the user-level signal handling |
| 682 | * stack-frames in one go after that. | 682 | * stack-frames in one go after that. |
| 683 | */ | 683 | */ |
| 684 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | 684 | int do_signal(struct pt_regs *regs, sigset_t *oldset) |
| 685 | { | 685 | { |
| 686 | siginfo_t info; | 686 | siginfo_t info; |
| 687 | int signr; | 687 | int signr; |
| 688 | struct k_sigaction ka; | 688 | struct k_sigaction ka; |
| 689 | 689 | ||
| 690 | /* | 690 | /* |
| 691 | * We want the common case to go fast, which | 691 | * We want the common case to go fast, which |
| 692 | * is why we may in certain cases get here from | 692 | * is why we may in certain cases get here from |
| 693 | * kernel mode. Just return without doing anything | 693 | * kernel mode. Just return without doing anything |
| 694 | * if so. | 694 | * if so. |
| 695 | */ | 695 | */ |
| 696 | if (!user_mode(regs)) | 696 | if (!user_mode(regs)) |
| 697 | return 1; | 697 | return 1; |
| 698 | 698 | ||
| 699 | if (try_to_freeze()) | 699 | if (try_to_freeze()) |
| 700 | goto no_signal; | 700 | goto no_signal; |
| 701 | 701 | ||
| 702 | if (!oldset) | 702 | if (!oldset) |
| 703 | oldset = ¤t->blocked; | 703 | oldset = ¤t->blocked; |
| 704 | 704 | ||
| 705 | signr = get_signal_to_deliver(&info, &ka, regs, 0); | 705 | signr = get_signal_to_deliver(&info, &ka, regs, 0); |
| 706 | 706 | ||
| 707 | if (signr > 0) { | 707 | if (signr > 0) { |
| 708 | /* Whee! Actually deliver the signal. */ | 708 | /* Whee! Actually deliver the signal. */ |
| 709 | handle_signal(signr, &info, &ka, oldset, regs); | 709 | handle_signal(signr, &info, &ka, oldset, regs); |
| 710 | return 1; | 710 | return 1; |
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | no_signal: | 713 | no_signal: |
| 714 | /* Did we come from a system call? */ | 714 | /* Did we come from a system call? */ |
| 715 | if (regs->syscall_nr >= 0) { | 715 | if (regs->syscall_nr >= 0) { |
| 716 | /* Restart the system call - no handlers present */ | 716 | /* Restart the system call - no handlers present */ |
| 717 | if (regs->regs[REG_RET] == -ERESTARTNOHAND || | 717 | if (regs->regs[REG_RET] == -ERESTARTNOHAND || |
| 718 | regs->regs[REG_RET] == -ERESTARTSYS || | 718 | regs->regs[REG_RET] == -ERESTARTSYS || |
| 719 | regs->regs[REG_RET] == -ERESTARTNOINTR) { | 719 | regs->regs[REG_RET] == -ERESTARTNOINTR) { |
| 720 | /* Decode Syscall # */ | 720 | /* Decode Syscall # */ |
| 721 | regs->regs[REG_RET] = regs->syscall_nr; | 721 | regs->regs[REG_RET] = regs->syscall_nr; |
| 722 | regs->pc -= 4; | 722 | regs->pc -= 4; |
| 723 | } | 723 | } |
| 724 | } | 724 | } |
| 725 | return 0; | 725 | return 0; |
| 726 | } | 726 | } |
| 727 | 727 |
arch/v850/kernel/signal.c
| 1 | /* | 1 | /* |
| 2 | * arch/v850/kernel/signal.c -- Signal handling | 2 | * arch/v850/kernel/signal.c -- Signal handling |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001,02,03 NEC Electronics Corporation | 4 | * Copyright (C) 2001,02,03 NEC Electronics Corporation |
| 5 | * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> | 5 | * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> |
| 6 | * Copyright (C) 1999,2000,2002 Niibe Yutaka & Kaz Kojima | 6 | * Copyright (C) 1999,2000,2002 Niibe Yutaka & Kaz Kojima |
| 7 | * Copyright (C) 1991,1992 Linus Torvalds | 7 | * Copyright (C) 1991,1992 Linus Torvalds |
| 8 | * | 8 | * |
| 9 | * This file is subject to the terms and conditions of the GNU General | 9 | * This file is subject to the terms and conditions of the GNU General |
| 10 | * Public License. See the file COPYING in the main directory of this | 10 | * Public License. See the file COPYING in the main directory of this |
| 11 | * archive for more details. | 11 | * archive for more details. |
| 12 | * | 12 | * |
| 13 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson | 13 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson |
| 14 | * | 14 | * |
| 15 | * This file was derived from the sh version, arch/sh/kernel/signal.c | 15 | * This file was derived from the sh version, arch/sh/kernel/signal.c |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
| 19 | #include <linux/smp.h> | 19 | #include <linux/smp.h> |
| 20 | #include <linux/smp_lock.h> | 20 | #include <linux/smp_lock.h> |
| 21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| 22 | #include <linux/signal.h> | 22 | #include <linux/signal.h> |
| 23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
| 24 | #include <linux/wait.h> | 24 | #include <linux/wait.h> |
| 25 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
| 26 | #include <linux/unistd.h> | 26 | #include <linux/unistd.h> |
| 27 | #include <linux/stddef.h> | 27 | #include <linux/stddef.h> |
| 28 | #include <linux/personality.h> | 28 | #include <linux/personality.h> |
| 29 | #include <linux/tty.h> | 29 | #include <linux/tty.h> |
| 30 | 30 | ||
| 31 | #include <asm/ucontext.h> | 31 | #include <asm/ucontext.h> |
| 32 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 33 | #include <asm/pgtable.h> | 33 | #include <asm/pgtable.h> |
| 34 | #include <asm/pgalloc.h> | 34 | #include <asm/pgalloc.h> |
| 35 | #include <asm/thread_info.h> | 35 | #include <asm/thread_info.h> |
| 36 | #include <asm/cacheflush.h> | 36 | #include <asm/cacheflush.h> |
| 37 | 37 | ||
| 38 | #define DEBUG_SIG 0 | 38 | #define DEBUG_SIG 0 |
| 39 | 39 | ||
| 40 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 40 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 41 | 41 | ||
| 42 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | 42 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); |
| 43 | 43 | ||
| 44 | /* | 44 | /* |
| 45 | * Atomically swap in the new signal mask, and wait for a signal. | 45 | * Atomically swap in the new signal mask, and wait for a signal. |
| 46 | */ | 46 | */ |
| 47 | asmlinkage int | 47 | asmlinkage int |
| 48 | sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs) | 48 | sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs) |
| 49 | { | 49 | { |
| 50 | sigset_t saveset; | 50 | sigset_t saveset; |
| 51 | 51 | ||
| 52 | mask &= _BLOCKABLE; | 52 | mask &= _BLOCKABLE; |
| 53 | spin_lock_irq(¤t->sighand->siglock); | 53 | spin_lock_irq(¤t->sighand->siglock); |
| 54 | saveset = current->blocked; | 54 | saveset = current->blocked; |
| 55 | siginitset(¤t->blocked, mask); | 55 | siginitset(¤t->blocked, mask); |
| 56 | recalc_sigpending(); | 56 | recalc_sigpending(); |
| 57 | spin_unlock_irq(¤t->sighand->siglock); | 57 | spin_unlock_irq(¤t->sighand->siglock); |
| 58 | 58 | ||
| 59 | regs->gpr[GPR_RVAL] = -EINTR; | 59 | regs->gpr[GPR_RVAL] = -EINTR; |
| 60 | while (1) { | 60 | while (1) { |
| 61 | current->state = TASK_INTERRUPTIBLE; | 61 | current->state = TASK_INTERRUPTIBLE; |
| 62 | schedule(); | 62 | schedule(); |
| 63 | if (do_signal(regs, &saveset)) | 63 | if (do_signal(regs, &saveset)) |
| 64 | return -EINTR; | 64 | return -EINTR; |
| 65 | } | 65 | } |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | asmlinkage int | 68 | asmlinkage int |
| 69 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, | 69 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, |
| 70 | struct pt_regs *regs) | 70 | struct pt_regs *regs) |
| 71 | { | 71 | { |
| 72 | sigset_t saveset, newset; | 72 | sigset_t saveset, newset; |
| 73 | 73 | ||
| 74 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 74 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
| 75 | if (sigsetsize != sizeof(sigset_t)) | 75 | if (sigsetsize != sizeof(sigset_t)) |
| 76 | return -EINVAL; | 76 | return -EINVAL; |
| 77 | 77 | ||
| 78 | if (copy_from_user(&newset, unewset, sizeof(newset))) | 78 | if (copy_from_user(&newset, unewset, sizeof(newset))) |
| 79 | return -EFAULT; | 79 | return -EFAULT; |
| 80 | sigdelsetmask(&newset, ~_BLOCKABLE); | 80 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 81 | spin_lock_irq(¤t->sighand->siglock); | 81 | spin_lock_irq(¤t->sighand->siglock); |
| 82 | saveset = current->blocked; | 82 | saveset = current->blocked; |
| 83 | current->blocked = newset; | 83 | current->blocked = newset; |
| 84 | recalc_sigpending(); | 84 | recalc_sigpending(); |
| 85 | spin_unlock_irq(¤t->sighand->siglock); | 85 | spin_unlock_irq(¤t->sighand->siglock); |
| 86 | 86 | ||
| 87 | regs->gpr[GPR_RVAL] = -EINTR; | 87 | regs->gpr[GPR_RVAL] = -EINTR; |
| 88 | while (1) { | 88 | while (1) { |
| 89 | current->state = TASK_INTERRUPTIBLE; | 89 | current->state = TASK_INTERRUPTIBLE; |
| 90 | schedule(); | 90 | schedule(); |
| 91 | if (do_signal(regs, &saveset)) | 91 | if (do_signal(regs, &saveset)) |
| 92 | return -EINTR; | 92 | return -EINTR; |
| 93 | } | 93 | } |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | asmlinkage int | 96 | asmlinkage int |
| 97 | sys_sigaction(int sig, const struct old_sigaction *act, | 97 | sys_sigaction(int sig, const struct old_sigaction *act, |
| 98 | struct old_sigaction *oact) | 98 | struct old_sigaction *oact) |
| 99 | { | 99 | { |
| 100 | struct k_sigaction new_ka, old_ka; | 100 | struct k_sigaction new_ka, old_ka; |
| 101 | int ret; | 101 | int ret; |
| 102 | 102 | ||
| 103 | if (act) { | 103 | if (act) { |
| 104 | old_sigset_t mask; | 104 | old_sigset_t mask; |
| 105 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 105 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
| 106 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 106 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
| 107 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 107 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) |
| 108 | return -EFAULT; | 108 | return -EFAULT; |
| 109 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | 109 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); |
| 110 | __get_user(mask, &act->sa_mask); | 110 | __get_user(mask, &act->sa_mask); |
| 111 | siginitset(&new_ka.sa.sa_mask, mask); | 111 | siginitset(&new_ka.sa.sa_mask, mask); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 114 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
| 115 | 115 | ||
| 116 | if (!ret && oact) { | 116 | if (!ret && oact) { |
| 117 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 117 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
| 118 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 118 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
| 119 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 119 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) |
| 120 | return -EFAULT; | 120 | return -EFAULT; |
| 121 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | 121 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
| 122 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | 122 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | return ret; | 125 | return ret; |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | asmlinkage int | 128 | asmlinkage int |
| 129 | sys_sigaltstack(const stack_t *uss, stack_t *uoss, | 129 | sys_sigaltstack(const stack_t *uss, stack_t *uoss, |
| 130 | struct pt_regs *regs) | 130 | struct pt_regs *regs) |
| 131 | { | 131 | { |
| 132 | return do_sigaltstack(uss, uoss, regs->gpr[GPR_SP]); | 132 | return do_sigaltstack(uss, uoss, regs->gpr[GPR_SP]); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | 135 | ||
| 136 | /* | 136 | /* |
| 137 | * Do a signal return; undo the signal stack. | 137 | * Do a signal return; undo the signal stack. |
| 138 | */ | 138 | */ |
| 139 | 139 | ||
| 140 | struct sigframe | 140 | struct sigframe |
| 141 | { | 141 | { |
| 142 | struct sigcontext sc; | 142 | struct sigcontext sc; |
| 143 | unsigned long extramask[_NSIG_WORDS-1]; | 143 | unsigned long extramask[_NSIG_WORDS-1]; |
| 144 | unsigned long tramp[2]; /* signal trampoline */ | 144 | unsigned long tramp[2]; /* signal trampoline */ |
| 145 | }; | 145 | }; |
| 146 | 146 | ||
| 147 | struct rt_sigframe | 147 | struct rt_sigframe |
| 148 | { | 148 | { |
| 149 | struct siginfo info; | 149 | struct siginfo info; |
| 150 | struct ucontext uc; | 150 | struct ucontext uc; |
| 151 | unsigned long tramp[2]; /* signal trampoline */ | 151 | unsigned long tramp[2]; /* signal trampoline */ |
| 152 | }; | 152 | }; |
| 153 | 153 | ||
| 154 | static int | 154 | static int |
| 155 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p) | 155 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p) |
| 156 | { | 156 | { |
| 157 | unsigned int err = 0; | 157 | unsigned int err = 0; |
| 158 | 158 | ||
| 159 | #define COPY(x) err |= __get_user(regs->x, &sc->regs.x) | 159 | #define COPY(x) err |= __get_user(regs->x, &sc->regs.x) |
| 160 | COPY(gpr[0]); COPY(gpr[1]); COPY(gpr[2]); COPY(gpr[3]); | 160 | COPY(gpr[0]); COPY(gpr[1]); COPY(gpr[2]); COPY(gpr[3]); |
| 161 | COPY(gpr[4]); COPY(gpr[5]); COPY(gpr[6]); COPY(gpr[7]); | 161 | COPY(gpr[4]); COPY(gpr[5]); COPY(gpr[6]); COPY(gpr[7]); |
| 162 | COPY(gpr[8]); COPY(gpr[9]); COPY(gpr[10]); COPY(gpr[11]); | 162 | COPY(gpr[8]); COPY(gpr[9]); COPY(gpr[10]); COPY(gpr[11]); |
| 163 | COPY(gpr[12]); COPY(gpr[13]); COPY(gpr[14]); COPY(gpr[15]); | 163 | COPY(gpr[12]); COPY(gpr[13]); COPY(gpr[14]); COPY(gpr[15]); |
| 164 | COPY(gpr[16]); COPY(gpr[17]); COPY(gpr[18]); COPY(gpr[19]); | 164 | COPY(gpr[16]); COPY(gpr[17]); COPY(gpr[18]); COPY(gpr[19]); |
| 165 | COPY(gpr[20]); COPY(gpr[21]); COPY(gpr[22]); COPY(gpr[23]); | 165 | COPY(gpr[20]); COPY(gpr[21]); COPY(gpr[22]); COPY(gpr[23]); |
| 166 | COPY(gpr[24]); COPY(gpr[25]); COPY(gpr[26]); COPY(gpr[27]); | 166 | COPY(gpr[24]); COPY(gpr[25]); COPY(gpr[26]); COPY(gpr[27]); |
| 167 | COPY(gpr[28]); COPY(gpr[29]); COPY(gpr[30]); COPY(gpr[31]); | 167 | COPY(gpr[28]); COPY(gpr[29]); COPY(gpr[30]); COPY(gpr[31]); |
| 168 | COPY(pc); COPY(psw); | 168 | COPY(pc); COPY(psw); |
| 169 | COPY(ctpc); COPY(ctpsw); COPY(ctbp); | 169 | COPY(ctpc); COPY(ctpsw); COPY(ctbp); |
| 170 | #undef COPY | 170 | #undef COPY |
| 171 | 171 | ||
| 172 | return err; | 172 | return err; |
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | asmlinkage int sys_sigreturn(struct pt_regs *regs) | 175 | asmlinkage int sys_sigreturn(struct pt_regs *regs) |
| 176 | { | 176 | { |
| 177 | struct sigframe *frame = (struct sigframe *)regs->gpr[GPR_SP]; | 177 | struct sigframe *frame = (struct sigframe *)regs->gpr[GPR_SP]; |
| 178 | sigset_t set; | 178 | sigset_t set; |
| 179 | int rval; | 179 | int rval; |
| 180 | 180 | ||
| 181 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 181 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 182 | goto badframe; | 182 | goto badframe; |
| 183 | 183 | ||
| 184 | if (__get_user(set.sig[0], &frame->sc.oldmask) | 184 | if (__get_user(set.sig[0], &frame->sc.oldmask) |
| 185 | || (_NSIG_WORDS > 1 | 185 | || (_NSIG_WORDS > 1 |
| 186 | && __copy_from_user(&set.sig[1], &frame->extramask, | 186 | && __copy_from_user(&set.sig[1], &frame->extramask, |
| 187 | sizeof(frame->extramask)))) | 187 | sizeof(frame->extramask)))) |
| 188 | goto badframe; | 188 | goto badframe; |
| 189 | 189 | ||
| 190 | sigdelsetmask(&set, ~_BLOCKABLE); | 190 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 191 | spin_lock_irq(¤t->sighand->siglock); | 191 | spin_lock_irq(¤t->sighand->siglock); |
| 192 | current->blocked = set; | 192 | current->blocked = set; |
| 193 | recalc_sigpending(); | 193 | recalc_sigpending(); |
| 194 | spin_unlock_irq(¤t->sighand->siglock); | 194 | spin_unlock_irq(¤t->sighand->siglock); |
| 195 | 195 | ||
| 196 | if (restore_sigcontext(regs, &frame->sc, &rval)) | 196 | if (restore_sigcontext(regs, &frame->sc, &rval)) |
| 197 | goto badframe; | 197 | goto badframe; |
| 198 | return rval; | 198 | return rval; |
| 199 | 199 | ||
| 200 | badframe: | 200 | badframe: |
| 201 | force_sig(SIGSEGV, current); | 201 | force_sig(SIGSEGV, current); |
| 202 | return 0; | 202 | return 0; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) | 205 | asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) |
| 206 | { | 206 | { |
| 207 | struct rt_sigframe *frame = (struct rt_sigframe *)regs->gpr[GPR_SP]; | 207 | struct rt_sigframe *frame = (struct rt_sigframe *)regs->gpr[GPR_SP]; |
| 208 | sigset_t set; | 208 | sigset_t set; |
| 209 | stack_t st; | 209 | stack_t st; |
| 210 | int rval; | 210 | int rval; |
| 211 | 211 | ||
| 212 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 212 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 213 | goto badframe; | 213 | goto badframe; |
| 214 | 214 | ||
| 215 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 215 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| 216 | goto badframe; | 216 | goto badframe; |
| 217 | 217 | ||
| 218 | sigdelsetmask(&set, ~_BLOCKABLE); | 218 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 219 | spin_lock_irq(¤t->sighand->siglock); | 219 | spin_lock_irq(¤t->sighand->siglock); |
| 220 | current->blocked = set; | 220 | current->blocked = set; |
| 221 | recalc_sigpending(); | 221 | recalc_sigpending(); |
| 222 | spin_unlock_irq(¤t->sighand->siglock); | 222 | spin_unlock_irq(¤t->sighand->siglock); |
| 223 | 223 | ||
| 224 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval)) | 224 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval)) |
| 225 | goto badframe; | 225 | goto badframe; |
| 226 | 226 | ||
| 227 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) | 227 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) |
| 228 | goto badframe; | 228 | goto badframe; |
| 229 | /* It is more difficult to avoid calling this function than to | 229 | /* It is more difficult to avoid calling this function than to |
| 230 | call it and ignore errors. */ | 230 | call it and ignore errors. */ |
| 231 | do_sigaltstack(&st, NULL, regs->gpr[GPR_SP]); | 231 | do_sigaltstack(&st, NULL, regs->gpr[GPR_SP]); |
| 232 | 232 | ||
| 233 | return rval; | 233 | return rval; |
| 234 | 234 | ||
| 235 | badframe: | 235 | badframe: |
| 236 | force_sig(SIGSEGV, current); | 236 | force_sig(SIGSEGV, current); |
| 237 | return 0; | 237 | return 0; |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | /* | 240 | /* |
| 241 | * Set up a signal frame. | 241 | * Set up a signal frame. |
| 242 | */ | 242 | */ |
| 243 | 243 | ||
| 244 | static int | 244 | static int |
| 245 | setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, | 245 | setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, |
| 246 | unsigned long mask) | 246 | unsigned long mask) |
| 247 | { | 247 | { |
| 248 | int err = 0; | 248 | int err = 0; |
| 249 | 249 | ||
| 250 | #define COPY(x) err |= __put_user(regs->x, &sc->regs.x) | 250 | #define COPY(x) err |= __put_user(regs->x, &sc->regs.x) |
| 251 | COPY(gpr[0]); COPY(gpr[1]); COPY(gpr[2]); COPY(gpr[3]); | 251 | COPY(gpr[0]); COPY(gpr[1]); COPY(gpr[2]); COPY(gpr[3]); |
| 252 | COPY(gpr[4]); COPY(gpr[5]); COPY(gpr[6]); COPY(gpr[7]); | 252 | COPY(gpr[4]); COPY(gpr[5]); COPY(gpr[6]); COPY(gpr[7]); |
| 253 | COPY(gpr[8]); COPY(gpr[9]); COPY(gpr[10]); COPY(gpr[11]); | 253 | COPY(gpr[8]); COPY(gpr[9]); COPY(gpr[10]); COPY(gpr[11]); |
| 254 | COPY(gpr[12]); COPY(gpr[13]); COPY(gpr[14]); COPY(gpr[15]); | 254 | COPY(gpr[12]); COPY(gpr[13]); COPY(gpr[14]); COPY(gpr[15]); |
| 255 | COPY(gpr[16]); COPY(gpr[17]); COPY(gpr[18]); COPY(gpr[19]); | 255 | COPY(gpr[16]); COPY(gpr[17]); COPY(gpr[18]); COPY(gpr[19]); |
| 256 | COPY(gpr[20]); COPY(gpr[21]); COPY(gpr[22]); COPY(gpr[23]); | 256 | COPY(gpr[20]); COPY(gpr[21]); COPY(gpr[22]); COPY(gpr[23]); |
| 257 | COPY(gpr[24]); COPY(gpr[25]); COPY(gpr[26]); COPY(gpr[27]); | 257 | COPY(gpr[24]); COPY(gpr[25]); COPY(gpr[26]); COPY(gpr[27]); |
| 258 | COPY(gpr[28]); COPY(gpr[29]); COPY(gpr[30]); COPY(gpr[31]); | 258 | COPY(gpr[28]); COPY(gpr[29]); COPY(gpr[30]); COPY(gpr[31]); |
| 259 | COPY(pc); COPY(psw); | 259 | COPY(pc); COPY(psw); |
| 260 | COPY(ctpc); COPY(ctpsw); COPY(ctbp); | 260 | COPY(ctpc); COPY(ctpsw); COPY(ctbp); |
| 261 | #undef COPY | 261 | #undef COPY |
| 262 | 262 | ||
| 263 | err |= __put_user(mask, &sc->oldmask); | 263 | err |= __put_user(mask, &sc->oldmask); |
| 264 | 264 | ||
| 265 | return err; | 265 | return err; |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | /* | 268 | /* |
| 269 | * Determine which stack to use.. | 269 | * Determine which stack to use.. |
| 270 | */ | 270 | */ |
| 271 | static inline void * | 271 | static inline void * |
| 272 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 272 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) |
| 273 | { | 273 | { |
| 274 | /* Default to using normal stack */ | 274 | /* Default to using normal stack */ |
| 275 | unsigned long sp = regs->gpr[GPR_SP]; | 275 | unsigned long sp = regs->gpr[GPR_SP]; |
| 276 | 276 | ||
| 277 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) | 277 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) |
| 278 | sp = current->sas_ss_sp + current->sas_ss_size; | 278 | sp = current->sas_ss_sp + current->sas_ss_size; |
| 279 | 279 | ||
| 280 | return (void *)((sp - frame_size) & -8UL); | 280 | return (void *)((sp - frame_size) & -8UL); |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | static void setup_frame(int sig, struct k_sigaction *ka, | 283 | static void setup_frame(int sig, struct k_sigaction *ka, |
| 284 | sigset_t *set, struct pt_regs *regs) | 284 | sigset_t *set, struct pt_regs *regs) |
| 285 | { | 285 | { |
| 286 | struct sigframe *frame; | 286 | struct sigframe *frame; |
| 287 | int err = 0; | 287 | int err = 0; |
| 288 | int signal; | 288 | int signal; |
| 289 | 289 | ||
| 290 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 290 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
| 291 | 291 | ||
| 292 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 292 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 293 | goto give_sigsegv; | 293 | goto give_sigsegv; |
| 294 | 294 | ||
| 295 | signal = current_thread_info()->exec_domain | 295 | signal = current_thread_info()->exec_domain |
| 296 | && current_thread_info()->exec_domain->signal_invmap | 296 | && current_thread_info()->exec_domain->signal_invmap |
| 297 | && sig < 32 | 297 | && sig < 32 |
| 298 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 298 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 299 | : sig; | 299 | : sig; |
| 300 | 300 | ||
| 301 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); | 301 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); |
| 302 | 302 | ||
| 303 | if (_NSIG_WORDS > 1) { | 303 | if (_NSIG_WORDS > 1) { |
| 304 | err |= __copy_to_user(frame->extramask, &set->sig[1], | 304 | err |= __copy_to_user(frame->extramask, &set->sig[1], |
| 305 | sizeof(frame->extramask)); | 305 | sizeof(frame->extramask)); |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | /* Set up to return from userspace. If provided, use a stub | 308 | /* Set up to return from userspace. If provided, use a stub |
| 309 | already in userspace. */ | 309 | already in userspace. */ |
| 310 | if (ka->sa.sa_flags & SA_RESTORER) { | 310 | if (ka->sa.sa_flags & SA_RESTORER) { |
| 311 | regs->gpr[GPR_LP] = (unsigned long) ka->sa.sa_restorer; | 311 | regs->gpr[GPR_LP] = (unsigned long) ka->sa.sa_restorer; |
| 312 | } else { | 312 | } else { |
| 313 | /* Note, these encodings are _little endian_! */ | 313 | /* Note, these encodings are _little endian_! */ |
| 314 | 314 | ||
| 315 | /* addi __NR_sigreturn, r0, r12 */ | 315 | /* addi __NR_sigreturn, r0, r12 */ |
| 316 | err |= __put_user(0x6600 | (__NR_sigreturn << 16), | 316 | err |= __put_user(0x6600 | (__NR_sigreturn << 16), |
| 317 | frame->tramp + 0); | 317 | frame->tramp + 0); |
| 318 | /* trap 0 */ | 318 | /* trap 0 */ |
| 319 | err |= __put_user(0x010007e0, | 319 | err |= __put_user(0x010007e0, |
| 320 | frame->tramp + 1); | 320 | frame->tramp + 1); |
| 321 | 321 | ||
| 322 | regs->gpr[GPR_LP] = (unsigned long)frame->tramp; | 322 | regs->gpr[GPR_LP] = (unsigned long)frame->tramp; |
| 323 | 323 | ||
| 324 | flush_cache_sigtramp (regs->gpr[GPR_LP]); | 324 | flush_cache_sigtramp (regs->gpr[GPR_LP]); |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | if (err) | 327 | if (err) |
| 328 | goto give_sigsegv; | 328 | goto give_sigsegv; |
| 329 | 329 | ||
| 330 | /* Set up registers for signal handler. */ | 330 | /* Set up registers for signal handler. */ |
| 331 | regs->pc = (v850_reg_t) ka->sa.sa_handler; | 331 | regs->pc = (v850_reg_t) ka->sa.sa_handler; |
| 332 | regs->gpr[GPR_SP] = (v850_reg_t)frame; | 332 | regs->gpr[GPR_SP] = (v850_reg_t)frame; |
| 333 | /* Signal handler args: */ | 333 | /* Signal handler args: */ |
| 334 | regs->gpr[GPR_ARG0] = signal; /* arg 0: signum */ | 334 | regs->gpr[GPR_ARG0] = signal; /* arg 0: signum */ |
| 335 | regs->gpr[GPR_ARG1] = (v850_reg_t)&frame->sc;/* arg 1: sigcontext */ | 335 | regs->gpr[GPR_ARG1] = (v850_reg_t)&frame->sc;/* arg 1: sigcontext */ |
| 336 | 336 | ||
| 337 | set_fs(USER_DS); | 337 | set_fs(USER_DS); |
| 338 | 338 | ||
| 339 | #if DEBUG_SIG | 339 | #if DEBUG_SIG |
| 340 | printk("SIG deliver (%s:%d): sp=%p pc=%08lx ra=%08lx\n", | 340 | printk("SIG deliver (%s:%d): sp=%p pc=%08lx ra=%08lx\n", |
| 341 | current->comm, current->pid, frame, regs->pc, ); | 341 | current->comm, current->pid, frame, regs->pc, ); |
| 342 | #endif | 342 | #endif |
| 343 | 343 | ||
| 344 | return; | 344 | return; |
| 345 | 345 | ||
| 346 | give_sigsegv: | 346 | give_sigsegv: |
| 347 | force_sigsegv(sig, current); | 347 | force_sigsegv(sig, current); |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 350 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 351 | sigset_t *set, struct pt_regs *regs) | 351 | sigset_t *set, struct pt_regs *regs) |
| 352 | { | 352 | { |
| 353 | struct rt_sigframe *frame; | 353 | struct rt_sigframe *frame; |
| 354 | int err = 0; | 354 | int err = 0; |
| 355 | int signal; | 355 | int signal; |
| 356 | 356 | ||
| 357 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 357 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
| 358 | 358 | ||
| 359 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 359 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 360 | goto give_sigsegv; | 360 | goto give_sigsegv; |
| 361 | 361 | ||
| 362 | signal = current_thread_info()->exec_domain | 362 | signal = current_thread_info()->exec_domain |
| 363 | && current_thread_info()->exec_domain->signal_invmap | 363 | && current_thread_info()->exec_domain->signal_invmap |
| 364 | && sig < 32 | 364 | && sig < 32 |
| 365 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 365 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 366 | : sig; | 366 | : sig; |
| 367 | 367 | ||
| 368 | err |= copy_siginfo_to_user(&frame->info, info); | 368 | err |= copy_siginfo_to_user(&frame->info, info); |
| 369 | 369 | ||
| 370 | /* Create the ucontext. */ | 370 | /* Create the ucontext. */ |
| 371 | err |= __put_user(0, &frame->uc.uc_flags); | 371 | err |= __put_user(0, &frame->uc.uc_flags); |
| 372 | err |= __put_user(0, &frame->uc.uc_link); | 372 | err |= __put_user(0, &frame->uc.uc_link); |
| 373 | err |= __put_user((void *)current->sas_ss_sp, | 373 | err |= __put_user((void *)current->sas_ss_sp, |
| 374 | &frame->uc.uc_stack.ss_sp); | 374 | &frame->uc.uc_stack.ss_sp); |
| 375 | err |= __put_user(sas_ss_flags(regs->gpr[GPR_SP]), | 375 | err |= __put_user(sas_ss_flags(regs->gpr[GPR_SP]), |
| 376 | &frame->uc.uc_stack.ss_flags); | 376 | &frame->uc.uc_stack.ss_flags); |
| 377 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 377 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
| 378 | err |= setup_sigcontext(&frame->uc.uc_mcontext, | 378 | err |= setup_sigcontext(&frame->uc.uc_mcontext, |
| 379 | regs, set->sig[0]); | 379 | regs, set->sig[0]); |
| 380 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 380 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 381 | 381 | ||
| 382 | /* Set up to return from userspace. If provided, use a stub | 382 | /* Set up to return from userspace. If provided, use a stub |
| 383 | already in userspace. */ | 383 | already in userspace. */ |
| 384 | if (ka->sa.sa_flags & SA_RESTORER) { | 384 | if (ka->sa.sa_flags & SA_RESTORER) { |
| 385 | regs->gpr[GPR_LP] = (unsigned long) ka->sa.sa_restorer; | 385 | regs->gpr[GPR_LP] = (unsigned long) ka->sa.sa_restorer; |
| 386 | } else { | 386 | } else { |
| 387 | /* Note, these encodings are _little endian_! */ | 387 | /* Note, these encodings are _little endian_! */ |
| 388 | 388 | ||
| 389 | /* addi __NR_sigreturn, r0, r12 */ | 389 | /* addi __NR_sigreturn, r0, r12 */ |
| 390 | err |= __put_user(0x6600 | (__NR_sigreturn << 16), | 390 | err |= __put_user(0x6600 | (__NR_sigreturn << 16), |
| 391 | frame->tramp + 0); | 391 | frame->tramp + 0); |
| 392 | /* trap 0 */ | 392 | /* trap 0 */ |
| 393 | err |= __put_user(0x010007e0, | 393 | err |= __put_user(0x010007e0, |
| 394 | frame->tramp + 1); | 394 | frame->tramp + 1); |
| 395 | 395 | ||
| 396 | regs->gpr[GPR_LP] = (unsigned long)frame->tramp; | 396 | regs->gpr[GPR_LP] = (unsigned long)frame->tramp; |
| 397 | 397 | ||
| 398 | flush_cache_sigtramp (regs->gpr[GPR_LP]); | 398 | flush_cache_sigtramp (regs->gpr[GPR_LP]); |
| 399 | } | 399 | } |
| 400 | 400 | ||
| 401 | if (err) | 401 | if (err) |
| 402 | goto give_sigsegv; | 402 | goto give_sigsegv; |
| 403 | 403 | ||
| 404 | /* Set up registers for signal handler. */ | 404 | /* Set up registers for signal handler. */ |
| 405 | regs->pc = (v850_reg_t) ka->sa.sa_handler; | 405 | regs->pc = (v850_reg_t) ka->sa.sa_handler; |
| 406 | regs->gpr[GPR_SP] = (v850_reg_t)frame; | 406 | regs->gpr[GPR_SP] = (v850_reg_t)frame; |
| 407 | /* Signal handler args: */ | 407 | /* Signal handler args: */ |
| 408 | regs->gpr[GPR_ARG0] = signal; /* arg 0: signum */ | 408 | regs->gpr[GPR_ARG0] = signal; /* arg 0: signum */ |
| 409 | regs->gpr[GPR_ARG1] = (v850_reg_t)&frame->info; /* arg 1: siginfo */ | 409 | regs->gpr[GPR_ARG1] = (v850_reg_t)&frame->info; /* arg 1: siginfo */ |
| 410 | regs->gpr[GPR_ARG2] = (v850_reg_t)&frame->uc; /* arg 2: ucontext */ | 410 | regs->gpr[GPR_ARG2] = (v850_reg_t)&frame->uc; /* arg 2: ucontext */ |
| 411 | 411 | ||
| 412 | set_fs(USER_DS); | 412 | set_fs(USER_DS); |
| 413 | 413 | ||
| 414 | #if DEBUG_SIG | 414 | #if DEBUG_SIG |
| 415 | printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", | 415 | printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
| 416 | current->comm, current->pid, frame, regs->pc, regs->pr); | 416 | current->comm, current->pid, frame, regs->pc, regs->pr); |
| 417 | #endif | 417 | #endif |
| 418 | 418 | ||
| 419 | return; | 419 | return; |
| 420 | 420 | ||
| 421 | give_sigsegv: | 421 | give_sigsegv: |
| 422 | force_sigsegv(sig, current); | 422 | force_sigsegv(sig, current); |
| 423 | } | 423 | } |
| 424 | 424 | ||
| 425 | /* | 425 | /* |
| 426 | * OK, we're invoking a handler | 426 | * OK, we're invoking a handler |
| 427 | */ | 427 | */ |
| 428 | 428 | ||
| 429 | static void | 429 | static void |
| 430 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, | 430 | handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, |
| 431 | sigset_t *oldset, struct pt_regs * regs) | 431 | sigset_t *oldset, struct pt_regs * regs) |
| 432 | { | 432 | { |
| 433 | /* Are we from a system call? */ | 433 | /* Are we from a system call? */ |
| 434 | if (PT_REGS_SYSCALL (regs)) { | 434 | if (PT_REGS_SYSCALL (regs)) { |
| 435 | /* If so, check system call restarting.. */ | 435 | /* If so, check system call restarting.. */ |
| 436 | switch (regs->gpr[GPR_RVAL]) { | 436 | switch (regs->gpr[GPR_RVAL]) { |
| 437 | case -ERESTART_RESTARTBLOCK: | 437 | case -ERESTART_RESTARTBLOCK: |
| 438 | current_thread_info()->restart_block.fn = | 438 | current_thread_info()->restart_block.fn = |
| 439 | do_no_restart_syscall; | 439 | do_no_restart_syscall; |
| 440 | /* fall through */ | 440 | /* fall through */ |
| 441 | case -ERESTARTNOHAND: | 441 | case -ERESTARTNOHAND: |
| 442 | regs->gpr[GPR_RVAL] = -EINTR; | 442 | regs->gpr[GPR_RVAL] = -EINTR; |
| 443 | break; | 443 | break; |
| 444 | 444 | ||
| 445 | case -ERESTARTSYS: | 445 | case -ERESTARTSYS: |
| 446 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 446 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
| 447 | regs->gpr[GPR_RVAL] = -EINTR; | 447 | regs->gpr[GPR_RVAL] = -EINTR; |
| 448 | break; | 448 | break; |
| 449 | } | 449 | } |
| 450 | /* fallthrough */ | 450 | /* fallthrough */ |
| 451 | case -ERESTARTNOINTR: | 451 | case -ERESTARTNOINTR: |
| 452 | regs->gpr[12] = PT_REGS_SYSCALL (regs); | 452 | regs->gpr[12] = PT_REGS_SYSCALL (regs); |
| 453 | regs->pc -= 4; /* Size of `trap 0' insn. */ | 453 | regs->pc -= 4; /* Size of `trap 0' insn. */ |
| 454 | } | 454 | } |
| 455 | 455 | ||
| 456 | PT_REGS_SET_SYSCALL (regs, 0); | 456 | PT_REGS_SET_SYSCALL (regs, 0); |
| 457 | } | 457 | } |
| 458 | 458 | ||
| 459 | /* Set up the stack frame */ | 459 | /* Set up the stack frame */ |
| 460 | if (ka->sa.sa_flags & SA_SIGINFO) | 460 | if (ka->sa.sa_flags & SA_SIGINFO) |
| 461 | setup_rt_frame(sig, ka, info, oldset, regs); | 461 | setup_rt_frame(sig, ka, info, oldset, regs); |
| 462 | else | 462 | else |
| 463 | setup_frame(sig, ka, oldset, regs); | 463 | setup_frame(sig, ka, oldset, regs); |
| 464 | 464 | ||
| 465 | spin_lock_irq(¤t->sighand->siglock); | 465 | spin_lock_irq(¤t->sighand->siglock); |
| 466 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 466 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
| 467 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 467 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
| 468 | sigaddset(¤t->blocked,sig); | 468 | sigaddset(¤t->blocked,sig); |
| 469 | recalc_sigpending(); | 469 | recalc_sigpending(); |
| 470 | spin_unlock_irq(¤t->sighand->siglock); | 470 | spin_unlock_irq(¤t->sighand->siglock); |
| 471 | } | 471 | } |
| 472 | 472 | ||
| 473 | /* | 473 | /* |
| 474 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 474 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 475 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 475 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 476 | * mistake. | 476 | * mistake. |
| 477 | * | 477 | * |
| 478 | * Note that we go through the signals twice: once to check the signals that | 478 | * Note that we go through the signals twice: once to check the signals that |
| 479 | * the kernel can handle, and then we build all the user-level signal handling | 479 | * the kernel can handle, and then we build all the user-level signal handling |
| 480 | * stack-frames in one go after that. | 480 | * stack-frames in one go after that. |
| 481 | */ | 481 | */ |
| 482 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | 482 | int do_signal(struct pt_regs *regs, sigset_t *oldset) |
| 483 | { | 483 | { |
| 484 | siginfo_t info; | 484 | siginfo_t info; |
| 485 | int signr; | 485 | int signr; |
| 486 | struct k_sigaction ka; | 486 | struct k_sigaction ka; |
| 487 | 487 | ||
| 488 | /* | 488 | /* |
| 489 | * We want the common case to go fast, which | 489 | * We want the common case to go fast, which |
| 490 | * is why we may in certain cases get here from | 490 | * is why we may in certain cases get here from |
| 491 | * kernel mode. Just return without doing anything | 491 | * kernel mode. Just return without doing anything |
| 492 | * if so. | 492 | * if so. |
| 493 | */ | 493 | */ |
| 494 | if (!user_mode(regs)) | 494 | if (!user_mode(regs)) |
| 495 | return 1; | 495 | return 1; |
| 496 | 496 | ||
| 497 | if (!oldset) | 497 | if (!oldset) |
| 498 | oldset = ¤t->blocked; | 498 | oldset = ¤t->blocked; |
| 499 | 499 | ||
| 500 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 500 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 501 | if (signr > 0) { | 501 | if (signr > 0) { |
| 502 | /* Whee! Actually deliver the signal. */ | 502 | /* Whee! Actually deliver the signal. */ |
| 503 | handle_signal(signr, &info, &ka, oldset, regs); | 503 | handle_signal(signr, &info, &ka, oldset, regs); |
| 504 | return 1; | 504 | return 1; |
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | /* Did we come from a system call? */ | 507 | /* Did we come from a system call? */ |
| 508 | if (PT_REGS_SYSCALL (regs)) { | 508 | if (PT_REGS_SYSCALL (regs)) { |
| 509 | int rval = (int)regs->gpr[GPR_RVAL]; | 509 | int rval = (int)regs->gpr[GPR_RVAL]; |
| 510 | /* Restart the system call - no handlers present */ | 510 | /* Restart the system call - no handlers present */ |
| 511 | if (rval == -ERESTARTNOHAND | 511 | if (rval == -ERESTARTNOHAND |
| 512 | || rval == -ERESTARTSYS | 512 | || rval == -ERESTARTSYS |
| 513 | || rval == -ERESTARTNOINTR) | 513 | || rval == -ERESTARTNOINTR) |
| 514 | { | 514 | { |
| 515 | regs->gpr[12] = PT_REGS_SYSCALL (regs); | 515 | regs->gpr[12] = PT_REGS_SYSCALL (regs); |
| 516 | regs->pc -= 4; /* Size of `trap 0' insn. */ | 516 | regs->pc -= 4; /* Size of `trap 0' insn. */ |
| 517 | } | 517 | } |
| 518 | else if (rval == -ERESTART_RESTARTBLOCK) { | 518 | else if (rval == -ERESTART_RESTARTBLOCK) { |
| 519 | regs->gpr[12] = __NR_restart_syscall; | 519 | regs->gpr[12] = __NR_restart_syscall; |
| 520 | regs->pc -= 4; /* Size of `trap 0' insn. */ | 520 | regs->pc -= 4; /* Size of `trap 0' insn. */ |
| 521 | } | 521 | } |
| 522 | } | 522 | } |
| 523 | return 0; | 523 | return 0; |
| 524 | } | 524 | } |
| 525 | 525 |
arch/xtensa/kernel/signal.c
| 1 | // TODO coprocessor stuff | 1 | // TODO coprocessor stuff |
| 2 | /* | 2 | /* |
| 3 | * linux/arch/xtensa/kernel/signal.c | 3 | * linux/arch/xtensa/kernel/signal.c |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 1991, 1992 Linus Torvalds | 5 | * Copyright (C) 1991, 1992 Linus Torvalds |
| 6 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson | 6 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson |
| 7 | * | 7 | * |
| 8 | * Joe Taylor <joe@tensilica.com> | 8 | * Joe Taylor <joe@tensilica.com> |
| 9 | * Chris Zankel <chris@zankel.net> | 9 | * Chris Zankel <chris@zankel.net> |
| 10 | * | 10 | * |
| 11 | * | 11 | * |
| 12 | * | 12 | * |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <xtensa/config/core.h> | 15 | #include <xtensa/config/core.h> |
| 16 | #include <xtensa/hal.h> | 16 | #include <xtensa/hal.h> |
| 17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
| 18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
| 19 | #include <linux/smp.h> | 19 | #include <linux/smp.h> |
| 20 | #include <linux/smp_lock.h> | 20 | #include <linux/smp_lock.h> |
| 21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| 22 | #include <linux/signal.h> | 22 | #include <linux/signal.h> |
| 23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
| 24 | #include <linux/wait.h> | 24 | #include <linux/wait.h> |
| 25 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
| 26 | #include <linux/unistd.h> | 26 | #include <linux/unistd.h> |
| 27 | #include <linux/stddef.h> | 27 | #include <linux/stddef.h> |
| 28 | #include <linux/personality.h> | 28 | #include <linux/personality.h> |
| 29 | #include <asm/ucontext.h> | 29 | #include <asm/ucontext.h> |
| 30 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
| 31 | #include <asm/pgtable.h> | 31 | #include <asm/pgtable.h> |
| 32 | #include <asm/cacheflush.h> | 32 | #include <asm/cacheflush.h> |
| 33 | 33 | ||
| 34 | #define DEBUG_SIG 0 | 34 | #define DEBUG_SIG 0 |
| 35 | 35 | ||
| 36 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 36 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 37 | 37 | ||
| 38 | asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, | 38 | asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, |
| 39 | struct rusage * ru); | 39 | struct rusage * ru); |
| 40 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | 40 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); |
| 41 | 41 | ||
| 42 | extern struct task_struct *coproc_owners[]; | 42 | extern struct task_struct *coproc_owners[]; |
| 43 | 43 | ||
| 44 | 44 | ||
| 45 | /* | 45 | /* |
| 46 | * Atomically swap in the new signal mask, and wait for a signal. | 46 | * Atomically swap in the new signal mask, and wait for a signal. |
| 47 | */ | 47 | */ |
| 48 | 48 | ||
| 49 | int sys_sigsuspend(struct pt_regs *regs) | 49 | int sys_sigsuspend(struct pt_regs *regs) |
| 50 | { | 50 | { |
| 51 | old_sigset_t mask = (old_sigset_t) regs->areg[3]; | 51 | old_sigset_t mask = (old_sigset_t) regs->areg[3]; |
| 52 | sigset_t saveset; | 52 | sigset_t saveset; |
| 53 | 53 | ||
| 54 | mask &= _BLOCKABLE; | 54 | mask &= _BLOCKABLE; |
| 55 | spin_lock_irq(¤t->sighand->siglock); | 55 | spin_lock_irq(¤t->sighand->siglock); |
| 56 | saveset = current->blocked; | 56 | saveset = current->blocked; |
| 57 | siginitset(¤t->blocked, mask); | 57 | siginitset(¤t->blocked, mask); |
| 58 | recalc_sigpending(); | 58 | recalc_sigpending(); |
| 59 | spin_unlock_irq(¤t->sighand->siglock); | 59 | spin_unlock_irq(¤t->sighand->siglock); |
| 60 | 60 | ||
| 61 | regs->areg[2] = -EINTR; | 61 | regs->areg[2] = -EINTR; |
| 62 | while (1) { | 62 | while (1) { |
| 63 | current->state = TASK_INTERRUPTIBLE; | 63 | current->state = TASK_INTERRUPTIBLE; |
| 64 | schedule(); | 64 | schedule(); |
| 65 | if (do_signal(regs, &saveset)) | 65 | if (do_signal(regs, &saveset)) |
| 66 | return -EINTR; | 66 | return -EINTR; |
| 67 | } | 67 | } |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | asmlinkage int | 70 | asmlinkage int |
| 71 | sys_rt_sigsuspend(struct pt_regs *regs) | 71 | sys_rt_sigsuspend(struct pt_regs *regs) |
| 72 | { | 72 | { |
| 73 | sigset_t *unewset = (sigset_t *) regs->areg[4]; | 73 | sigset_t *unewset = (sigset_t *) regs->areg[4]; |
| 74 | size_t sigsetsize = (size_t) regs->areg[3]; | 74 | size_t sigsetsize = (size_t) regs->areg[3]; |
| 75 | sigset_t saveset, newset; | 75 | sigset_t saveset, newset; |
| 76 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 76 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
| 77 | if (sigsetsize != sizeof(sigset_t)) | 77 | if (sigsetsize != sizeof(sigset_t)) |
| 78 | return -EINVAL; | 78 | return -EINVAL; |
| 79 | 79 | ||
| 80 | if (copy_from_user(&newset, unewset, sizeof(newset))) | 80 | if (copy_from_user(&newset, unewset, sizeof(newset))) |
| 81 | return -EFAULT; | 81 | return -EFAULT; |
| 82 | sigdelsetmask(&newset, ~_BLOCKABLE); | 82 | sigdelsetmask(&newset, ~_BLOCKABLE); |
| 83 | spin_lock_irq(¤t->sighand->siglock); | 83 | spin_lock_irq(¤t->sighand->siglock); |
| 84 | saveset = current->blocked; | 84 | saveset = current->blocked; |
| 85 | current->blocked = newset; | 85 | current->blocked = newset; |
| 86 | recalc_sigpending(); | 86 | recalc_sigpending(); |
| 87 | spin_unlock_irq(¤t->sighand->siglock); | 87 | spin_unlock_irq(¤t->sighand->siglock); |
| 88 | 88 | ||
| 89 | regs->areg[2] = -EINTR; | 89 | regs->areg[2] = -EINTR; |
| 90 | while (1) { | 90 | while (1) { |
| 91 | current->state = TASK_INTERRUPTIBLE; | 91 | current->state = TASK_INTERRUPTIBLE; |
| 92 | schedule(); | 92 | schedule(); |
| 93 | if (do_signal(regs, &saveset)) | 93 | if (do_signal(regs, &saveset)) |
| 94 | return -EINTR; | 94 | return -EINTR; |
| 95 | } | 95 | } |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | asmlinkage int | 98 | asmlinkage int |
| 99 | sys_sigaction(int sig, const struct old_sigaction *act, | 99 | sys_sigaction(int sig, const struct old_sigaction *act, |
| 100 | struct old_sigaction *oact) | 100 | struct old_sigaction *oact) |
| 101 | { | 101 | { |
| 102 | struct k_sigaction new_ka, old_ka; | 102 | struct k_sigaction new_ka, old_ka; |
| 103 | int ret; | 103 | int ret; |
| 104 | 104 | ||
| 105 | if (act) { | 105 | if (act) { |
| 106 | old_sigset_t mask; | 106 | old_sigset_t mask; |
| 107 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 107 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
| 108 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 108 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
| 109 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 109 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) |
| 110 | return -EFAULT; | 110 | return -EFAULT; |
| 111 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | 111 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); |
| 112 | __get_user(mask, &act->sa_mask); | 112 | __get_user(mask, &act->sa_mask); |
| 113 | siginitset(&new_ka.sa.sa_mask, mask); | 113 | siginitset(&new_ka.sa.sa_mask, mask); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | 116 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
| 117 | 117 | ||
| 118 | if (!ret && oact) { | 118 | if (!ret && oact) { |
| 119 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 119 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
| 120 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 120 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
| 121 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 121 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) |
| 122 | return -EFAULT; | 122 | return -EFAULT; |
| 123 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | 123 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
| 124 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | 124 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | return ret; | 127 | return ret; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | asmlinkage int | 130 | asmlinkage int |
| 131 | sys_sigaltstack(struct pt_regs *regs) | 131 | sys_sigaltstack(struct pt_regs *regs) |
| 132 | { | 132 | { |
| 133 | const stack_t *uss = (stack_t *) regs->areg[4]; | 133 | const stack_t *uss = (stack_t *) regs->areg[4]; |
| 134 | stack_t *uoss = (stack_t *) regs->areg[3]; | 134 | stack_t *uoss = (stack_t *) regs->areg[3]; |
| 135 | 135 | ||
| 136 | if (regs->depc > 64) | 136 | if (regs->depc > 64) |
| 137 | panic ("Double exception sys_sigreturn\n"); | 137 | panic ("Double exception sys_sigreturn\n"); |
| 138 | 138 | ||
| 139 | 139 | ||
| 140 | return do_sigaltstack(uss, uoss, regs->areg[1]); | 140 | return do_sigaltstack(uss, uoss, regs->areg[1]); |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | 143 | ||
| 144 | /* | 144 | /* |
| 145 | * Do a signal return; undo the signal stack. | 145 | * Do a signal return; undo the signal stack. |
| 146 | */ | 146 | */ |
| 147 | 147 | ||
| 148 | struct sigframe | 148 | struct sigframe |
| 149 | { | 149 | { |
| 150 | struct sigcontext sc; | 150 | struct sigcontext sc; |
| 151 | struct _cpstate cpstate; | 151 | struct _cpstate cpstate; |
| 152 | unsigned long extramask[_NSIG_WORDS-1]; | 152 | unsigned long extramask[_NSIG_WORDS-1]; |
| 153 | unsigned char retcode[6]; | 153 | unsigned char retcode[6]; |
| 154 | unsigned int reserved[4]; /* Reserved area for chaining */ | 154 | unsigned int reserved[4]; /* Reserved area for chaining */ |
| 155 | unsigned int window[4]; /* Window of 4 registers for initial context */ | 155 | unsigned int window[4]; /* Window of 4 registers for initial context */ |
| 156 | }; | 156 | }; |
| 157 | 157 | ||
| 158 | struct rt_sigframe | 158 | struct rt_sigframe |
| 159 | { | 159 | { |
| 160 | struct siginfo info; | 160 | struct siginfo info; |
| 161 | struct ucontext uc; | 161 | struct ucontext uc; |
| 162 | struct _cpstate cpstate; | 162 | struct _cpstate cpstate; |
| 163 | unsigned char retcode[6]; | 163 | unsigned char retcode[6]; |
| 164 | unsigned int reserved[4]; /* Reserved area for chaining */ | 164 | unsigned int reserved[4]; /* Reserved area for chaining */ |
| 165 | unsigned int window[4]; /* Window of 4 registers for initial context */ | 165 | unsigned int window[4]; /* Window of 4 registers for initial context */ |
| 166 | }; | 166 | }; |
| 167 | 167 | ||
| 168 | extern void release_all_cp (struct task_struct *); | 168 | extern void release_all_cp (struct task_struct *); |
| 169 | 169 | ||
| 170 | 170 | ||
| 171 | // FIXME restore_cpextra | 171 | // FIXME restore_cpextra |
| 172 | static inline int | 172 | static inline int |
| 173 | restore_cpextra (struct _cpstate *buf) | 173 | restore_cpextra (struct _cpstate *buf) |
| 174 | { | 174 | { |
| 175 | #if 0 | 175 | #if 0 |
| 176 | /* The signal handler may have used coprocessors in which | 176 | /* The signal handler may have used coprocessors in which |
| 177 | * case they are still enabled. We disable them to force a | 177 | * case they are still enabled. We disable them to force a |
| 178 | * reloading of the original task's CP state by the lazy | 178 | * reloading of the original task's CP state by the lazy |
| 179 | * context-switching mechanisms of CP exception handling. | 179 | * context-switching mechanisms of CP exception handling. |
| 180 | * Also, we essentially discard any coprocessor state that the | 180 | * Also, we essentially discard any coprocessor state that the |
| 181 | * signal handler created. */ | 181 | * signal handler created. */ |
| 182 | 182 | ||
| 183 | struct task_struct *tsk = current; | 183 | struct task_struct *tsk = current; |
| 184 | release_all_cp(tsk); | 184 | release_all_cp(tsk); |
| 185 | return __copy_from_user(tsk->thread.cpextra, buf, XTENSA_CP_EXTRA_SIZE); | 185 | return __copy_from_user(tsk->thread.cpextra, buf, XTENSA_CP_EXTRA_SIZE); |
| 186 | #endif | 186 | #endif |
| 187 | return 0; | 187 | return 0; |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | /* Note: We don't copy double exception 'tregs', we have to finish double exc. first before we return to signal handler! This dbl.exc.handler might cause another double exception, but I think we are fine as the situation is the same as if we had returned to the signal handerl and got an interrupt immediately... | 190 | /* Note: We don't copy double exception 'tregs', we have to finish double exc. first before we return to signal handler! This dbl.exc.handler might cause another double exception, but I think we are fine as the situation is the same as if we had returned to the signal handerl and got an interrupt immediately... |
| 191 | */ | 191 | */ |
| 192 | 192 | ||
| 193 | 193 | ||
| 194 | static int | 194 | static int |
| 195 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) | 195 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) |
| 196 | { | 196 | { |
| 197 | struct thread_struct *thread; | 197 | struct thread_struct *thread; |
| 198 | unsigned int err = 0; | 198 | unsigned int err = 0; |
| 199 | unsigned long ps; | 199 | unsigned long ps; |
| 200 | struct _cpstate *buf; | 200 | struct _cpstate *buf; |
| 201 | 201 | ||
| 202 | #define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) | 202 | #define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) |
| 203 | COPY(pc); | 203 | COPY(pc); |
| 204 | COPY(depc); | 204 | COPY(depc); |
| 205 | COPY(wmask); | 205 | COPY(wmask); |
| 206 | COPY(lbeg); | 206 | COPY(lbeg); |
| 207 | COPY(lend); | 207 | COPY(lend); |
| 208 | COPY(lcount); | 208 | COPY(lcount); |
| 209 | COPY(sar); | 209 | COPY(sar); |
| 210 | COPY(windowbase); | 210 | COPY(windowbase); |
| 211 | COPY(windowstart); | 211 | COPY(windowstart); |
| 212 | #undef COPY | 212 | #undef COPY |
| 213 | 213 | ||
| 214 | /* For PS, restore only PS.CALLINC. | 214 | /* For PS, restore only PS.CALLINC. |
| 215 | * Assume that all other bits are either the same as for the signal | 215 | * Assume that all other bits are either the same as for the signal |
| 216 | * handler, or the user mode value doesn't matter (e.g. PS.OWB). | 216 | * handler, or the user mode value doesn't matter (e.g. PS.OWB). |
| 217 | */ | 217 | */ |
| 218 | err |= __get_user(ps, &sc->sc_ps); | 218 | err |= __get_user(ps, &sc->sc_ps); |
| 219 | regs->ps = (regs->ps & ~XCHAL_PS_CALLINC_MASK) | 219 | regs->ps = (regs->ps & ~XCHAL_PS_CALLINC_MASK) |
| 220 | | (ps & XCHAL_PS_CALLINC_MASK); | 220 | | (ps & XCHAL_PS_CALLINC_MASK); |
| 221 | 221 | ||
| 222 | /* Additional corruption checks */ | 222 | /* Additional corruption checks */ |
| 223 | 223 | ||
| 224 | if ((regs->windowbase >= (XCHAL_NUM_AREGS/4)) | 224 | if ((regs->windowbase >= (XCHAL_NUM_AREGS/4)) |
| 225 | || ((regs->windowstart & ~((1<<(XCHAL_NUM_AREGS/4)) - 1)) != 0) ) | 225 | || ((regs->windowstart & ~((1<<(XCHAL_NUM_AREGS/4)) - 1)) != 0) ) |
| 226 | err = 1; | 226 | err = 1; |
| 227 | if ((regs->lcount > 0) | 227 | if ((regs->lcount > 0) |
| 228 | && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) ) | 228 | && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) ) |
| 229 | err = 1; | 229 | err = 1; |
| 230 | 230 | ||
| 231 | /* Restore extended register state. | 231 | /* Restore extended register state. |
| 232 | * See struct thread_struct in processor.h. | 232 | * See struct thread_struct in processor.h. |
| 233 | */ | 233 | */ |
| 234 | thread = ¤t->thread; | 234 | thread = ¤t->thread; |
| 235 | 235 | ||
| 236 | err |= __copy_from_user (regs->areg, sc->sc_areg, XCHAL_NUM_AREGS*4); | 236 | err |= __copy_from_user (regs->areg, sc->sc_areg, XCHAL_NUM_AREGS*4); |
| 237 | err |= __get_user(buf, &sc->sc_cpstate); | 237 | err |= __get_user(buf, &sc->sc_cpstate); |
| 238 | if (buf) { | 238 | if (buf) { |
| 239 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) | 239 | if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) |
| 240 | goto badframe; | 240 | goto badframe; |
| 241 | err |= restore_cpextra(buf); | 241 | err |= restore_cpextra(buf); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | regs->syscall = -1; /* disable syscall checks */ | 244 | regs->syscall = -1; /* disable syscall checks */ |
| 245 | return err; | 245 | return err; |
| 246 | 246 | ||
| 247 | badframe: | 247 | badframe: |
| 248 | return 1; | 248 | return 1; |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | static inline void | 251 | static inline void |
| 252 | flush_my_cpstate(struct task_struct *tsk) | 252 | flush_my_cpstate(struct task_struct *tsk) |
| 253 | { | 253 | { |
| 254 | unsigned long flags; | 254 | unsigned long flags; |
| 255 | local_irq_save(flags); | 255 | local_irq_save(flags); |
| 256 | 256 | ||
| 257 | #if 0 // FIXME | 257 | #if 0 // FIXME |
| 258 | for (i = 0; i < XCHAL_CP_NUM; i++) { | 258 | for (i = 0; i < XCHAL_CP_NUM; i++) { |
| 259 | if (tsk == coproc_owners[i]) { | 259 | if (tsk == coproc_owners[i]) { |
| 260 | xthal_validate_cp(i); | 260 | xthal_validate_cp(i); |
| 261 | xthal_save_cpregs(tsk->thread.cpregs_ptr[i], i); | 261 | xthal_save_cpregs(tsk->thread.cpregs_ptr[i], i); |
| 262 | 262 | ||
| 263 | /* Invalidate and "disown" the cp to allow | 263 | /* Invalidate and "disown" the cp to allow |
| 264 | * callers the chance to reset cp state in the | 264 | * callers the chance to reset cp state in the |
| 265 | * task_struct. */ | 265 | * task_struct. */ |
| 266 | 266 | ||
| 267 | xthal_invalidate_cp(i); | 267 | xthal_invalidate_cp(i); |
| 268 | coproc_owners[i] = 0; | 268 | coproc_owners[i] = 0; |
| 269 | } | 269 | } |
| 270 | } | 270 | } |
| 271 | #endif | 271 | #endif |
| 272 | local_irq_restore(flags); | 272 | local_irq_restore(flags); |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | /* Return codes: | 275 | /* Return codes: |
| 276 | 0: nothing saved | 276 | 0: nothing saved |
| 277 | 1: stuff to save, successful | 277 | 1: stuff to save, successful |
| 278 | -1: stuff to save, error happened | 278 | -1: stuff to save, error happened |
| 279 | */ | 279 | */ |
| 280 | static int | 280 | static int |
| 281 | save_cpextra (struct _cpstate *buf) | 281 | save_cpextra (struct _cpstate *buf) |
| 282 | { | 282 | { |
| 283 | #if (XCHAL_EXTRA_SA_SIZE == 0) && (XCHAL_CP_NUM == 0) | 283 | #if (XCHAL_EXTRA_SA_SIZE == 0) && (XCHAL_CP_NUM == 0) |
| 284 | return 0; | 284 | return 0; |
| 285 | #else | 285 | #else |
| 286 | 286 | ||
| 287 | /* FIXME: If a task has never used a coprocessor, there is | 287 | /* FIXME: If a task has never used a coprocessor, there is |
| 288 | * no need to save and restore anything. Tracking this | 288 | * no need to save and restore anything. Tracking this |
| 289 | * information would allow us to optimize this section. | 289 | * information would allow us to optimize this section. |
| 290 | * Perhaps we can use current->used_math or (current->flags & | 290 | * Perhaps we can use current->used_math or (current->flags & |
| 291 | * PF_USEDFPU) or define a new field in the thread | 291 | * PF_USEDFPU) or define a new field in the thread |
| 292 | * structure. */ | 292 | * structure. */ |
| 293 | 293 | ||
| 294 | /* We flush any live, task-owned cp state to the task_struct, | 294 | /* We flush any live, task-owned cp state to the task_struct, |
| 295 | * then copy it all to the sigframe. Then we clear all | 295 | * then copy it all to the sigframe. Then we clear all |
| 296 | * cp/extra state in the task_struct, effectively | 296 | * cp/extra state in the task_struct, effectively |
| 297 | * clearing/resetting all cp/extra state for the signal | 297 | * clearing/resetting all cp/extra state for the signal |
| 298 | * handler (cp-exception handling will load these new values | 298 | * handler (cp-exception handling will load these new values |
| 299 | * into the cp/extra registers.) This step is important for | 299 | * into the cp/extra registers.) This step is important for |
| 300 | * things like a floating-point cp, where the OS must reset | 300 | * things like a floating-point cp, where the OS must reset |
| 301 | * the FCR to the default rounding mode. */ | 301 | * the FCR to the default rounding mode. */ |
| 302 | 302 | ||
| 303 | int err = 0; | 303 | int err = 0; |
| 304 | struct task_struct *tsk = current; | 304 | struct task_struct *tsk = current; |
| 305 | 305 | ||
| 306 | flush_my_cpstate(tsk); | 306 | flush_my_cpstate(tsk); |
| 307 | /* Note that we just copy everything: 'extra' and 'cp' state together.*/ | 307 | /* Note that we just copy everything: 'extra' and 'cp' state together.*/ |
| 308 | err |= __copy_to_user(buf, tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE); | 308 | err |= __copy_to_user(buf, tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE); |
| 309 | memset(tsk->thread.cp_save, 0, XTENSA_CP_EXTRA_SIZE); | 309 | memset(tsk->thread.cp_save, 0, XTENSA_CP_EXTRA_SIZE); |
| 310 | 310 | ||
| 311 | #if (XTENSA_CP_EXTRA_SIZE == 0) | 311 | #if (XTENSA_CP_EXTRA_SIZE == 0) |
| 312 | #error Sanity check on memset above, cpextra_size should not be zero. | 312 | #error Sanity check on memset above, cpextra_size should not be zero. |
| 313 | #endif | 313 | #endif |
| 314 | 314 | ||
| 315 | return err ? -1 : 1; | 315 | return err ? -1 : 1; |
| 316 | #endif | 316 | #endif |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | static int | 319 | static int |
| 320 | setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate, | 320 | setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate, |
| 321 | struct pt_regs *regs, unsigned long mask) | 321 | struct pt_regs *regs, unsigned long mask) |
| 322 | { | 322 | { |
| 323 | struct thread_struct *thread; | 323 | struct thread_struct *thread; |
| 324 | int err = 0; | 324 | int err = 0; |
| 325 | 325 | ||
| 326 | //printk("setup_sigcontext\n"); | 326 | //printk("setup_sigcontext\n"); |
| 327 | #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) | 327 | #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) |
| 328 | COPY(pc); | 328 | COPY(pc); |
| 329 | COPY(ps); | 329 | COPY(ps); |
| 330 | COPY(depc); | 330 | COPY(depc); |
| 331 | COPY(wmask); | 331 | COPY(wmask); |
| 332 | COPY(lbeg); | 332 | COPY(lbeg); |
| 333 | COPY(lend); | 333 | COPY(lend); |
| 334 | COPY(lcount); | 334 | COPY(lcount); |
| 335 | COPY(sar); | 335 | COPY(sar); |
| 336 | COPY(windowbase); | 336 | COPY(windowbase); |
| 337 | COPY(windowstart); | 337 | COPY(windowstart); |
| 338 | #undef COPY | 338 | #undef COPY |
| 339 | 339 | ||
| 340 | /* Save extended register state. | 340 | /* Save extended register state. |
| 341 | * See struct thread_struct in processor.h. | 341 | * See struct thread_struct in processor.h. |
| 342 | */ | 342 | */ |
| 343 | thread = ¤t->thread; | 343 | thread = ¤t->thread; |
| 344 | err |= __copy_to_user (sc->sc_areg, regs->areg, XCHAL_NUM_AREGS * 4); | 344 | err |= __copy_to_user (sc->sc_areg, regs->areg, XCHAL_NUM_AREGS * 4); |
| 345 | err |= save_cpextra(cpstate); | 345 | err |= save_cpextra(cpstate); |
| 346 | err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); | 346 | err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); |
| 347 | /* non-iBCS2 extensions.. */ | 347 | /* non-iBCS2 extensions.. */ |
| 348 | err |= __put_user(mask, &sc->oldmask); | 348 | err |= __put_user(mask, &sc->oldmask); |
| 349 | 349 | ||
| 350 | return err; | 350 | return err; |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | asmlinkage int sys_sigreturn(struct pt_regs *regs) | 353 | asmlinkage int sys_sigreturn(struct pt_regs *regs) |
| 354 | { | 354 | { |
| 355 | struct sigframe *frame = (struct sigframe *)regs->areg[1]; | 355 | struct sigframe *frame = (struct sigframe *)regs->areg[1]; |
| 356 | sigset_t set; | 356 | sigset_t set; |
| 357 | if (regs->depc > 64) | 357 | if (regs->depc > 64) |
| 358 | panic ("Double exception sys_sigreturn\n"); | 358 | panic ("Double exception sys_sigreturn\n"); |
| 359 | 359 | ||
| 360 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 360 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 361 | goto badframe; | 361 | goto badframe; |
| 362 | 362 | ||
| 363 | if (__get_user(set.sig[0], &frame->sc.oldmask) | 363 | if (__get_user(set.sig[0], &frame->sc.oldmask) |
| 364 | || (_NSIG_WORDS > 1 | 364 | || (_NSIG_WORDS > 1 |
| 365 | && __copy_from_user(&set.sig[1], &frame->extramask, | 365 | && __copy_from_user(&set.sig[1], &frame->extramask, |
| 366 | sizeof(frame->extramask)))) | 366 | sizeof(frame->extramask)))) |
| 367 | goto badframe; | 367 | goto badframe; |
| 368 | 368 | ||
| 369 | sigdelsetmask(&set, ~_BLOCKABLE); | 369 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 370 | 370 | ||
| 371 | spin_lock_irq(¤t->sighand->siglock); | 371 | spin_lock_irq(¤t->sighand->siglock); |
| 372 | current->blocked = set; | 372 | current->blocked = set; |
| 373 | recalc_sigpending(); | 373 | recalc_sigpending(); |
| 374 | spin_unlock_irq(¤t->sighand->siglock); | 374 | spin_unlock_irq(¤t->sighand->siglock); |
| 375 | 375 | ||
| 376 | if (restore_sigcontext(regs, &frame->sc)) | 376 | if (restore_sigcontext(regs, &frame->sc)) |
| 377 | goto badframe; | 377 | goto badframe; |
| 378 | return regs->areg[2]; | 378 | return regs->areg[2]; |
| 379 | 379 | ||
| 380 | badframe: | 380 | badframe: |
| 381 | force_sig(SIGSEGV, current); | 381 | force_sig(SIGSEGV, current); |
| 382 | return 0; | 382 | return 0; |
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) | 385 | asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) |
| 386 | { | 386 | { |
| 387 | struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1]; | 387 | struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1]; |
| 388 | sigset_t set; | 388 | sigset_t set; |
| 389 | stack_t st; | 389 | stack_t st; |
| 390 | int ret; | 390 | int ret; |
| 391 | if (regs->depc > 64) | 391 | if (regs->depc > 64) |
| 392 | { | 392 | { |
| 393 | printk("!!!!!!! DEPC !!!!!!!\n"); | 393 | printk("!!!!!!! DEPC !!!!!!!\n"); |
| 394 | return 0; | 394 | return 0; |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 397 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
| 398 | goto badframe; | 398 | goto badframe; |
| 399 | 399 | ||
| 400 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | 400 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
| 401 | goto badframe; | 401 | goto badframe; |
| 402 | 402 | ||
| 403 | sigdelsetmask(&set, ~_BLOCKABLE); | 403 | sigdelsetmask(&set, ~_BLOCKABLE); |
| 404 | spin_lock_irq(¤t->sighand->siglock); | 404 | spin_lock_irq(¤t->sighand->siglock); |
| 405 | current->blocked = set; | 405 | current->blocked = set; |
| 406 | recalc_sigpending(); | 406 | recalc_sigpending(); |
| 407 | spin_unlock_irq(¤t->sighand->siglock); | 407 | spin_unlock_irq(¤t->sighand->siglock); |
| 408 | 408 | ||
| 409 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) | 409 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) |
| 410 | goto badframe; | 410 | goto badframe; |
| 411 | ret = regs->areg[2]; | 411 | ret = regs->areg[2]; |
| 412 | 412 | ||
| 413 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) | 413 | if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) |
| 414 | goto badframe; | 414 | goto badframe; |
| 415 | /* It is more difficult to avoid calling this function than to | 415 | /* It is more difficult to avoid calling this function than to |
| 416 | call it and ignore errors. */ | 416 | call it and ignore errors. */ |
| 417 | do_sigaltstack(&st, NULL, regs->areg[1]); | 417 | do_sigaltstack(&st, NULL, regs->areg[1]); |
| 418 | 418 | ||
| 419 | return ret; | 419 | return ret; |
| 420 | 420 | ||
| 421 | badframe: | 421 | badframe: |
| 422 | force_sig(SIGSEGV, current); | 422 | force_sig(SIGSEGV, current); |
| 423 | return 0; | 423 | return 0; |
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | /* | 426 | /* |
| 427 | * Set up a signal frame. | 427 | * Set up a signal frame. |
| 428 | */ | 428 | */ |
| 429 | 429 | ||
| 430 | /* | 430 | /* |
| 431 | * Determine which stack to use.. | 431 | * Determine which stack to use.. |
| 432 | */ | 432 | */ |
| 433 | static inline void * | 433 | static inline void * |
| 434 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | 434 | get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) |
| 435 | { | 435 | { |
| 436 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) | 436 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) |
| 437 | sp = current->sas_ss_sp + current->sas_ss_size; | 437 | sp = current->sas_ss_sp + current->sas_ss_size; |
| 438 | 438 | ||
| 439 | return (void *)((sp - frame_size) & -16ul); | 439 | return (void *)((sp - frame_size) & -16ul); |
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | #define USE_SIGRETURN 0 | 442 | #define USE_SIGRETURN 0 |
| 443 | #define USE_RT_SIGRETURN 1 | 443 | #define USE_RT_SIGRETURN 1 |
| 444 | 444 | ||
| 445 | static int | 445 | static int |
| 446 | gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn) | 446 | gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn) |
| 447 | { | 447 | { |
| 448 | unsigned int retcall; | 448 | unsigned int retcall; |
| 449 | int err = 0; | 449 | int err = 0; |
| 450 | 450 | ||
| 451 | #if 0 | 451 | #if 0 |
| 452 | /* Ignoring SA_RESTORER for now; it's supposed to be obsolete, | 452 | /* Ignoring SA_RESTORER for now; it's supposed to be obsolete, |
| 453 | * and the xtensa glibc doesn't use it. | 453 | * and the xtensa glibc doesn't use it. |
| 454 | */ | 454 | */ |
| 455 | if (ka->sa.sa_flags & SA_RESTORER) { | 455 | if (ka->sa.sa_flags & SA_RESTORER) { |
| 456 | regs->pr = (unsigned long) ka->sa.sa_restorer; | 456 | regs->pr = (unsigned long) ka->sa.sa_restorer; |
| 457 | } else | 457 | } else |
| 458 | #endif /* 0 */ | 458 | #endif /* 0 */ |
| 459 | { | 459 | { |
| 460 | 460 | ||
| 461 | #if (__NR_sigreturn > 255) || (__NR_rt_sigreturn > 255) | 461 | #if (__NR_sigreturn > 255) || (__NR_rt_sigreturn > 255) |
| 462 | 462 | ||
| 463 | /* The 12-bit immediate is really split up within the 24-bit MOVI | 463 | /* The 12-bit immediate is really split up within the 24-bit MOVI |
| 464 | * instruction. As long as the above system call numbers fit within | 464 | * instruction. As long as the above system call numbers fit within |
| 465 | * 8-bits, the following code works fine. See the Xtensa ISA for | 465 | * 8-bits, the following code works fine. See the Xtensa ISA for |
| 466 | * details. | 466 | * details. |
| 467 | */ | 467 | */ |
| 468 | 468 | ||
| 469 | #error Generating the MOVI instruction below breaks! | 469 | #error Generating the MOVI instruction below breaks! |
| 470 | #endif | 470 | #endif |
| 471 | 471 | ||
| 472 | retcall = use_rt_sigreturn ? __NR_rt_sigreturn : __NR_sigreturn; | 472 | retcall = use_rt_sigreturn ? __NR_rt_sigreturn : __NR_sigreturn; |
| 473 | 473 | ||
| 474 | #ifdef __XTENSA_EB__ /* Big Endian version */ | 474 | #ifdef __XTENSA_EB__ /* Big Endian version */ |
| 475 | /* Generate instruction: MOVI a2, retcall */ | 475 | /* Generate instruction: MOVI a2, retcall */ |
| 476 | err |= __put_user(0x22, &codemem[0]); | 476 | err |= __put_user(0x22, &codemem[0]); |
| 477 | err |= __put_user(0x0a, &codemem[1]); | 477 | err |= __put_user(0x0a, &codemem[1]); |
| 478 | err |= __put_user(retcall, &codemem[2]); | 478 | err |= __put_user(retcall, &codemem[2]); |
| 479 | /* Generate instruction: SYSCALL */ | 479 | /* Generate instruction: SYSCALL */ |
| 480 | err |= __put_user(0x00, &codemem[3]); | 480 | err |= __put_user(0x00, &codemem[3]); |
| 481 | err |= __put_user(0x05, &codemem[4]); | 481 | err |= __put_user(0x05, &codemem[4]); |
| 482 | err |= __put_user(0x00, &codemem[5]); | 482 | err |= __put_user(0x00, &codemem[5]); |
| 483 | 483 | ||
| 484 | #elif defined __XTENSA_EL__ /* Little Endian version */ | 484 | #elif defined __XTENSA_EL__ /* Little Endian version */ |
| 485 | /* Generate instruction: MOVI a2, retcall */ | 485 | /* Generate instruction: MOVI a2, retcall */ |
| 486 | err |= __put_user(0x22, &codemem[0]); | 486 | err |= __put_user(0x22, &codemem[0]); |
| 487 | err |= __put_user(0xa0, &codemem[1]); | 487 | err |= __put_user(0xa0, &codemem[1]); |
| 488 | err |= __put_user(retcall, &codemem[2]); | 488 | err |= __put_user(retcall, &codemem[2]); |
| 489 | /* Generate instruction: SYSCALL */ | 489 | /* Generate instruction: SYSCALL */ |
| 490 | err |= __put_user(0x00, &codemem[3]); | 490 | err |= __put_user(0x00, &codemem[3]); |
| 491 | err |= __put_user(0x50, &codemem[4]); | 491 | err |= __put_user(0x50, &codemem[4]); |
| 492 | err |= __put_user(0x00, &codemem[5]); | 492 | err |= __put_user(0x00, &codemem[5]); |
| 493 | #else | 493 | #else |
| 494 | #error Must use compiler for Xtensa processors. | 494 | #error Must use compiler for Xtensa processors. |
| 495 | #endif | 495 | #endif |
| 496 | } | 496 | } |
| 497 | 497 | ||
| 498 | /* Flush generated code out of the data cache */ | 498 | /* Flush generated code out of the data cache */ |
| 499 | 499 | ||
| 500 | if (err == 0) | 500 | if (err == 0) |
| 501 | __flush_invalidate_cache_range((unsigned long)codemem, 6UL); | 501 | __flush_invalidate_cache_range((unsigned long)codemem, 6UL); |
| 502 | 502 | ||
| 503 | return err; | 503 | return err; |
| 504 | } | 504 | } |
| 505 | 505 | ||
| 506 | static void | 506 | static void |
| 507 | set_thread_state(struct pt_regs *regs, void *stack, unsigned char *retaddr, | 507 | set_thread_state(struct pt_regs *regs, void *stack, unsigned char *retaddr, |
| 508 | void *handler, unsigned long arg1, void *arg2, void *arg3) | 508 | void *handler, unsigned long arg1, void *arg2, void *arg3) |
| 509 | { | 509 | { |
| 510 | /* Set up registers for signal handler */ | 510 | /* Set up registers for signal handler */ |
| 511 | start_thread(regs, (unsigned long) handler, (unsigned long) stack); | 511 | start_thread(regs, (unsigned long) handler, (unsigned long) stack); |
| 512 | 512 | ||
| 513 | /* Set up a stack frame for a call4 | 513 | /* Set up a stack frame for a call4 |
| 514 | * Note: PS.CALLINC is set to one by start_thread | 514 | * Note: PS.CALLINC is set to one by start_thread |
| 515 | */ | 515 | */ |
| 516 | regs->areg[4] = (((unsigned long) retaddr) & 0x3fffffff) | 0x40000000; | 516 | regs->areg[4] = (((unsigned long) retaddr) & 0x3fffffff) | 0x40000000; |
| 517 | regs->areg[6] = arg1; | 517 | regs->areg[6] = arg1; |
| 518 | regs->areg[7] = (unsigned long) arg2; | 518 | regs->areg[7] = (unsigned long) arg2; |
| 519 | regs->areg[8] = (unsigned long) arg3; | 519 | regs->areg[8] = (unsigned long) arg3; |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | static void setup_frame(int sig, struct k_sigaction *ka, | 522 | static void setup_frame(int sig, struct k_sigaction *ka, |
| 523 | sigset_t *set, struct pt_regs *regs) | 523 | sigset_t *set, struct pt_regs *regs) |
| 524 | { | 524 | { |
| 525 | struct sigframe *frame; | 525 | struct sigframe *frame; |
| 526 | int err = 0; | 526 | int err = 0; |
| 527 | int signal; | 527 | int signal; |
| 528 | 528 | ||
| 529 | frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); | 529 | frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); |
| 530 | if (regs->depc > 64) | 530 | if (regs->depc > 64) |
| 531 | { | 531 | { |
| 532 | printk("!!!!!!! DEPC !!!!!!!\n"); | 532 | printk("!!!!!!! DEPC !!!!!!!\n"); |
| 533 | return; | 533 | return; |
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | 536 | ||
| 537 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 537 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 538 | goto give_sigsegv; | 538 | goto give_sigsegv; |
| 539 | 539 | ||
| 540 | signal = current_thread_info()->exec_domain | 540 | signal = current_thread_info()->exec_domain |
| 541 | && current_thread_info()->exec_domain->signal_invmap | 541 | && current_thread_info()->exec_domain->signal_invmap |
| 542 | && sig < 32 | 542 | && sig < 32 |
| 543 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 543 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 544 | : sig; | 544 | : sig; |
| 545 | 545 | ||
| 546 | err |= setup_sigcontext(&frame->sc, &frame->cpstate, regs, set->sig[0]); | 546 | err |= setup_sigcontext(&frame->sc, &frame->cpstate, regs, set->sig[0]); |
| 547 | 547 | ||
| 548 | if (_NSIG_WORDS > 1) { | 548 | if (_NSIG_WORDS > 1) { |
| 549 | err |= __copy_to_user(frame->extramask, &set->sig[1], | 549 | err |= __copy_to_user(frame->extramask, &set->sig[1], |
| 550 | sizeof(frame->extramask)); | 550 | sizeof(frame->extramask)); |
| 551 | } | 551 | } |
| 552 | 552 | ||
| 553 | /* Create sys_sigreturn syscall in stack frame */ | 553 | /* Create sys_sigreturn syscall in stack frame */ |
| 554 | err |= gen_return_code(frame->retcode, USE_SIGRETURN); | 554 | err |= gen_return_code(frame->retcode, USE_SIGRETURN); |
| 555 | 555 | ||
| 556 | if (err) | 556 | if (err) |
| 557 | goto give_sigsegv; | 557 | goto give_sigsegv; |
| 558 | 558 | ||
| 559 | /* Create signal handler execution context. | 559 | /* Create signal handler execution context. |
| 560 | * Return context not modified until this point. | 560 | * Return context not modified until this point. |
| 561 | */ | 561 | */ |
| 562 | set_thread_state(regs, frame, frame->retcode, | 562 | set_thread_state(regs, frame, frame->retcode, |
| 563 | ka->sa.sa_handler, signal, &frame->sc, NULL); | 563 | ka->sa.sa_handler, signal, &frame->sc, NULL); |
| 564 | 564 | ||
| 565 | /* Set access mode to USER_DS. Nomenclature is outdated, but | 565 | /* Set access mode to USER_DS. Nomenclature is outdated, but |
| 566 | * functionality is used in uaccess.h | 566 | * functionality is used in uaccess.h |
| 567 | */ | 567 | */ |
| 568 | set_fs(USER_DS); | 568 | set_fs(USER_DS); |
| 569 | 569 | ||
| 570 | 570 | ||
| 571 | #if DEBUG_SIG | 571 | #if DEBUG_SIG |
| 572 | printk("SIG deliver (%s:%d): signal=%d sp=%p pc=%08x\n", | 572 | printk("SIG deliver (%s:%d): signal=%d sp=%p pc=%08x\n", |
| 573 | current->comm, current->pid, signal, frame, regs->pc); | 573 | current->comm, current->pid, signal, frame, regs->pc); |
| 574 | #endif | 574 | #endif |
| 575 | 575 | ||
| 576 | return; | 576 | return; |
| 577 | 577 | ||
| 578 | give_sigsegv: | 578 | give_sigsegv: |
| 579 | if (sig == SIGSEGV) | 579 | if (sig == SIGSEGV) |
| 580 | ka->sa.sa_handler = SIG_DFL; | 580 | ka->sa.sa_handler = SIG_DFL; |
| 581 | force_sig(SIGSEGV, current); | 581 | force_sig(SIGSEGV, current); |
| 582 | } | 582 | } |
| 583 | 583 | ||
| 584 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 584 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
| 585 | sigset_t *set, struct pt_regs *regs) | 585 | sigset_t *set, struct pt_regs *regs) |
| 586 | { | 586 | { |
| 587 | struct rt_sigframe *frame; | 587 | struct rt_sigframe *frame; |
| 588 | int err = 0; | 588 | int err = 0; |
| 589 | int signal; | 589 | int signal; |
| 590 | 590 | ||
| 591 | frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); | 591 | frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); |
| 592 | if (regs->depc > 64) | 592 | if (regs->depc > 64) |
| 593 | panic ("Double exception sys_sigreturn\n"); | 593 | panic ("Double exception sys_sigreturn\n"); |
| 594 | 594 | ||
| 595 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 595 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
| 596 | goto give_sigsegv; | 596 | goto give_sigsegv; |
| 597 | 597 | ||
| 598 | signal = current_thread_info()->exec_domain | 598 | signal = current_thread_info()->exec_domain |
| 599 | && current_thread_info()->exec_domain->signal_invmap | 599 | && current_thread_info()->exec_domain->signal_invmap |
| 600 | && sig < 32 | 600 | && sig < 32 |
| 601 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 601 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
| 602 | : sig; | 602 | : sig; |
| 603 | 603 | ||
| 604 | err |= copy_siginfo_to_user(&frame->info, info); | 604 | err |= copy_siginfo_to_user(&frame->info, info); |
| 605 | 605 | ||
| 606 | /* Create the ucontext. */ | 606 | /* Create the ucontext. */ |
| 607 | err |= __put_user(0, &frame->uc.uc_flags); | 607 | err |= __put_user(0, &frame->uc.uc_flags); |
| 608 | err |= __put_user(0, &frame->uc.uc_link); | 608 | err |= __put_user(0, &frame->uc.uc_link); |
| 609 | err |= __put_user((void *)current->sas_ss_sp, | 609 | err |= __put_user((void *)current->sas_ss_sp, |
| 610 | &frame->uc.uc_stack.ss_sp); | 610 | &frame->uc.uc_stack.ss_sp); |
| 611 | err |= __put_user(sas_ss_flags(regs->areg[1]), | 611 | err |= __put_user(sas_ss_flags(regs->areg[1]), |
| 612 | &frame->uc.uc_stack.ss_flags); | 612 | &frame->uc.uc_stack.ss_flags); |
| 613 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 613 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
| 614 | err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate, | 614 | err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate, |
| 615 | regs, set->sig[0]); | 615 | regs, set->sig[0]); |
| 616 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 616 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
| 617 | 617 | ||
| 618 | /* Create sys_rt_sigreturn syscall in stack frame */ | 618 | /* Create sys_rt_sigreturn syscall in stack frame */ |
| 619 | err |= gen_return_code(frame->retcode, USE_RT_SIGRETURN); | 619 | err |= gen_return_code(frame->retcode, USE_RT_SIGRETURN); |
| 620 | 620 | ||
| 621 | if (err) | 621 | if (err) |
| 622 | goto give_sigsegv; | 622 | goto give_sigsegv; |
| 623 | 623 | ||
| 624 | /* Create signal handler execution context. | 624 | /* Create signal handler execution context. |
| 625 | * Return context not modified until this point. | 625 | * Return context not modified until this point. |
| 626 | */ | 626 | */ |
| 627 | set_thread_state(regs, frame, frame->retcode, | 627 | set_thread_state(regs, frame, frame->retcode, |
| 628 | ka->sa.sa_handler, signal, &frame->info, &frame->uc); | 628 | ka->sa.sa_handler, signal, &frame->info, &frame->uc); |
| 629 | 629 | ||
| 630 | /* Set access mode to USER_DS. Nomenclature is outdated, but | 630 | /* Set access mode to USER_DS. Nomenclature is outdated, but |
| 631 | * functionality is used in uaccess.h | 631 | * functionality is used in uaccess.h |
| 632 | */ | 632 | */ |
| 633 | set_fs(USER_DS); | 633 | set_fs(USER_DS); |
| 634 | 634 | ||
| 635 | #if DEBUG_SIG | 635 | #if DEBUG_SIG |
| 636 | printk("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08x\n", | 636 | printk("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08x\n", |
| 637 | current->comm, current->pid, signal, frame, regs->pc); | 637 | current->comm, current->pid, signal, frame, regs->pc); |
| 638 | #endif | 638 | #endif |
| 639 | 639 | ||
| 640 | return; | 640 | return; |
| 641 | 641 | ||
| 642 | give_sigsegv: | 642 | give_sigsegv: |
| 643 | if (sig == SIGSEGV) | 643 | if (sig == SIGSEGV) |
| 644 | ka->sa.sa_handler = SIG_DFL; | 644 | ka->sa.sa_handler = SIG_DFL; |
| 645 | force_sig(SIGSEGV, current); | 645 | force_sig(SIGSEGV, current); |
| 646 | } | 646 | } |
| 647 | 647 | ||
| 648 | 648 | ||
| 649 | 649 | ||
| 650 | /* | 650 | /* |
| 651 | * Note that 'init' is a special process: it doesn't get signals it doesn't | 651 | * Note that 'init' is a special process: it doesn't get signals it doesn't |
| 652 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 652 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
| 653 | * mistake. | 653 | * mistake. |
| 654 | * | 654 | * |
| 655 | * Note that we go through the signals twice: once to check the signals that | 655 | * Note that we go through the signals twice: once to check the signals that |
| 656 | * the kernel can handle, and then we build all the user-level signal handling | 656 | * the kernel can handle, and then we build all the user-level signal handling |
| 657 | * stack-frames in one go after that. | 657 | * stack-frames in one go after that. |
| 658 | */ | 658 | */ |
| 659 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | 659 | int do_signal(struct pt_regs *regs, sigset_t *oldset) |
| 660 | { | 660 | { |
| 661 | siginfo_t info; | 661 | siginfo_t info; |
| 662 | int signr; | 662 | int signr; |
| 663 | struct k_sigaction ka; | 663 | struct k_sigaction ka; |
| 664 | 664 | ||
| 665 | if (!oldset) | 665 | if (!oldset) |
| 666 | oldset = ¤t->blocked; | 666 | oldset = ¤t->blocked; |
| 667 | 667 | ||
| 668 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 668 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
| 669 | 669 | ||
| 670 | /* Are we from a system call? */ | 670 | /* Are we from a system call? */ |
| 671 | if (regs->syscall >= 0) { | 671 | if (regs->syscall >= 0) { |
| 672 | /* If so, check system call restarting.. */ | 672 | /* If so, check system call restarting.. */ |
| 673 | switch (regs->areg[2]) { | 673 | switch (regs->areg[2]) { |
| 674 | case ERESTARTNOHAND: | 674 | case ERESTARTNOHAND: |
| 675 | case ERESTART_RESTARTBLOCK: | 675 | case ERESTART_RESTARTBLOCK: |
| 676 | regs->areg[2] = -EINTR; | 676 | regs->areg[2] = -EINTR; |
| 677 | break; | 677 | break; |
| 678 | 678 | ||
| 679 | case ERESTARTSYS: | 679 | case ERESTARTSYS: |
| 680 | if (!(ka.sa.sa_flags & SA_RESTART)) { | 680 | if (!(ka.sa.sa_flags & SA_RESTART)) { |
| 681 | regs->areg[2] = -EINTR; | 681 | regs->areg[2] = -EINTR; |
| 682 | break; | 682 | break; |
| 683 | } | 683 | } |
| 684 | /* fallthrough */ | 684 | /* fallthrough */ |
| 685 | case ERESTARTNOINTR: | 685 | case ERESTARTNOINTR: |
| 686 | regs->areg[2] = regs->syscall; | 686 | regs->areg[2] = regs->syscall; |
| 687 | regs->pc -= 3; | 687 | regs->pc -= 3; |
| 688 | } | 688 | } |
| 689 | } | 689 | } |
| 690 | 690 | ||
| 691 | if (signr == 0) | 691 | if (signr == 0) |
| 692 | return 0; /* no signals delivered */ | 692 | return 0; /* no signals delivered */ |
| 693 | 693 | ||
| 694 | /* Whee! Actually deliver the signal. */ | 694 | /* Whee! Actually deliver the signal. */ |
| 695 | 695 | ||
| 696 | /* Set up the stack frame */ | 696 | /* Set up the stack frame */ |
| 697 | if (ka.sa.sa_flags & SA_SIGINFO) | 697 | if (ka.sa.sa_flags & SA_SIGINFO) |
| 698 | setup_rt_frame(signr, &ka, &info, oldset, regs); | 698 | setup_rt_frame(signr, &ka, &info, oldset, regs); |
| 699 | else | 699 | else |
| 700 | setup_frame(signr, &ka, oldset, regs); | 700 | setup_frame(signr, &ka, oldset, regs); |
| 701 | 701 | ||
| 702 | if (ka.sa.sa_flags & SA_ONESHOT) | 702 | if (ka.sa.sa_flags & SA_ONESHOT) |
| 703 | ka.sa.sa_handler = SIG_DFL; | 703 | ka.sa.sa_handler = SIG_DFL; |
| 704 | 704 | ||
| 705 | spin_lock_irq(¤t->sighand->siglock); | 705 | spin_lock_irq(¤t->sighand->siglock); |
| 706 | sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); | 706 | sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); |
| 707 | if (!(ka.sa.sa_flags & SA_NODEFER)) | 707 | if (!(ka.sa.sa_flags & SA_NODEFER)) |
| 708 | sigaddset(¤t->blocked, signr); | 708 | sigaddset(¤t->blocked, signr); |
| 709 | recalc_sigpending(); | 709 | recalc_sigpending(); |
| 710 | spin_unlock_irq(¤t->sighand->siglock); | 710 | spin_unlock_irq(¤t->sighand->siglock); |
| 711 | return 1; | 711 | return 1; |
| 712 | } | 712 | } |
| 713 | 713 |