Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

microblaze_v8: Signal support

Reviewed-by: Ingo Molnar <mingo@elte.hu>
Acked-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
Acked-by: John Linn <john.linn@xilinx.com>
Acked-by: John Williams <john.williams@petalogix.com>
Signed-off-by: Michal Simek <monstr@monstr.eu>

+703
+165
arch/microblaze/include/asm/signal.h
··· 1 + /* 2 + * Copyright (C) 2006 Atmark Techno, Inc. 3 + * Yasushi SHOJI <yashi@atmark-techno.com> 4 + * Tetsuya OHKAWA <tetsuya@atmark-techno.com> 5 + * 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 8 + * for more details. 9 + */ 10 + 11 + #ifndef _ASM_MICROBLAZE_SIGNAL_H 12 + #define _ASM_MICROBLAZE_SIGNAL_H 13 + 14 + #define SIGHUP 1 15 + #define SIGINT 2 16 + #define SIGQUIT 3 17 + #define SIGILL 4 18 + #define SIGTRAP 5 19 + #define SIGABRT 6 20 + #define SIGIOT 6 21 + #define SIGBUS 7 22 + #define SIGFPE 8 23 + #define SIGKILL 9 24 + #define SIGUSR1 10 25 + #define SIGSEGV 11 26 + #define SIGUSR2 12 27 + #define SIGPIPE 13 28 + #define SIGALRM 14 29 + #define SIGTERM 15 30 + #define SIGSTKFLT 16 31 + #define SIGCHLD 17 32 + #define SIGCONT 18 33 + #define SIGSTOP 19 34 + #define SIGTSTP 20 35 + #define SIGTTIN 21 36 + #define SIGTTOU 22 37 + #define SIGURG 23 38 + #define SIGXCPU 24 39 + #define SIGXFSZ 25 40 + #define SIGVTALRM 26 41 + #define SIGPROF 27 42 + #define SIGWINCH 28 43 + #define SIGIO 29 44 + #define SIGPOLL SIGIO 45 + /* 46 + #define SIGLOST 29 47 + */ 48 + #define SIGPWR 30 49 + #define SIGSYS 31 50 + #define SIGUNUSED 31 51 + 52 + /* These should not be considered constants from userland. */ 53 + #define SIGRTMIN 32 54 + #define SIGRTMAX _NSIG 55 + 56 + /* 57 + * SA_FLAGS values: 58 + * 59 + * SA_ONSTACK indicates that a registered stack_t will be used. 60 + * SA_RESTART flag to get restarting signals (which were the default long ago) 61 + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. 62 + * SA_RESETHAND clears the handler when the signal is delivered. 63 + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. 64 + * SA_NODEFER prevents the current signal from being masked in the handler. 65 + * 66 + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single 67 + * Unix names RESETHAND and NODEFER respectively. 68 + */ 69 + #define SA_NOCLDSTOP 0x00000001 70 + #define SA_NOCLDWAIT 0x00000002 71 + #define SA_SIGINFO 0x00000004 72 + #define SA_ONSTACK 0x08000000 73 + #define SA_RESTART 0x10000000 74 + #define SA_NODEFER 0x40000000 75 + #define SA_RESETHAND 0x80000000 76 + 77 + #define SA_NOMASK SA_NODEFER 78 + #define SA_ONESHOT SA_RESETHAND 79 + 80 + #define SA_RESTORER 0x04000000 81 + 82 + /* 83 + * sigaltstack controls 84 + */ 85 + #define SS_ONSTACK 1 86 + #define SS_DISABLE 2 87 + 88 + #define MINSIGSTKSZ 2048 89 + #define SIGSTKSZ 8192 90 + 91 + # ifndef __ASSEMBLY__ 92 + # include <linux/types.h> 93 + # include <asm-generic/signal.h> 94 + 95 + /* Avoid too many header ordering problems. */ 96 + struct siginfo; 97 + 98 + # ifdef __KERNEL__ 99 + /* 100 + * Most things should be clean enough to redefine this at will, if care 101 + * is taken to make libc match. 102 + */ 103 + # define _NSIG 64 104 + # define _NSIG_BPW 32 105 + # define _NSIG_WORDS (_NSIG / _NSIG_BPW) 106 + 107 + typedef unsigned long old_sigset_t; /* at least 32 bits */ 108 + 109 + typedef struct { 110 + unsigned long sig[_NSIG_WORDS]; 111 + } sigset_t; 112 + 113 + struct old_sigaction { 114 + __sighandler_t sa_handler; 115 + old_sigset_t sa_mask; 116 + unsigned long sa_flags; 117 + void (*sa_restorer)(void); 118 + }; 119 + 120 + struct sigaction { 121 + __sighandler_t sa_handler; 122 + unsigned long sa_flags; 123 + void (*sa_restorer)(void); 124 + sigset_t sa_mask; /* mask last for extensibility */ 125 + }; 126 + 127 + struct k_sigaction { 128 + struct sigaction sa; 129 + }; 130 + 131 + # include <asm/sigcontext.h> 132 + # undef __HAVE_ARCH_SIG_BITOPS 133 + 134 + # define ptrace_signal_deliver(regs, cookie) do { } while (0) 135 + 136 + # else /* !__KERNEL__ */ 137 + 138 + /* Here we must cater to libcs that poke about in kernel headers. */ 139 + 140 + # define NSIG 32 141 + typedef unsigned long sigset_t; 142 + 143 + struct sigaction { 144 + union { 145 + __sighandler_t _sa_handler; 146 + void (*_sa_sigaction)(int, struct siginfo *, void *); 147 + } _u; 148 + sigset_t sa_mask; 149 + unsigned long sa_flags; 150 + void (*sa_restorer)(void); 151 + }; 152 + 153 + # define sa_handler _u._sa_handler 154 + # define sa_sigaction _u._sa_sigaction 155 + 156 + # endif /* __KERNEL__ */ 157 + 158 + typedef struct sigaltstack { 159 + void *ss_sp; 160 + int ss_flags; 161 + size_t ss_size; 162 + } stack_t; 163 + 164 + # endif /* __ASSEMBLY__ */ 165 + #endif /* _ASM_MICROBLAZE_SIGNAL_H */
+538
arch/microblaze/kernel/signal.c
··· 1 + /* 2 + * Signal handling 3 + * 4 + * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu> 5 + * Copyright (C) 2008-2009 PetaLogix 6 + * Copyright (C) 2003,2004 John Williams <jwilliams@itee.uq.edu.au> 7 + * Copyright (C) 2001 NEC Corporation 8 + * Copyright (C) 2001 Miles Bader <miles@gnu.org> 9 + * Copyright (C) 1999,2000 Niibe Yutaka & Kaz Kojima 10 + * Copyright (C) 1991,1992 Linus Torvalds 11 + * 12 + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson 13 + * 14 + * This file was was derived from the sh version, arch/sh/kernel/signal.c 15 + * 16 + * This file is subject to the terms and conditions of the GNU General 17 + * Public License. See the file COPYING in the main directory of this 18 + * archive for more details. 19 + */ 20 + 21 + #include <linux/sched.h> 22 + #include <linux/mm.h> 23 + #include <linux/smp.h> 24 + #include <linux/smp_lock.h> 25 + #include <linux/kernel.h> 26 + #include <linux/signal.h> 27 + #include <linux/errno.h> 28 + #include <linux/wait.h> 29 + #include <linux/ptrace.h> 30 + #include <linux/unistd.h> 31 + #include <linux/stddef.h> 32 + #include <linux/personality.h> 33 + #include <linux/percpu.h> 34 + #include <linux/linkage.h> 35 + #include <asm/entry.h> 36 + #include <asm/ucontext.h> 37 + #include <linux/uaccess.h> 38 + #include <asm/pgtable.h> 39 + #include <asm/pgalloc.h> 40 + #include <linux/signal.h> 41 + #include <linux/syscalls.h> 42 + #include <asm/cacheflush.h> 43 + #include <asm/syscalls.h> 44 + 45 + #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 46 + 47 + asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall); 48 + 49 + /* 50 + * Atomically swap in the new signal mask, and wait for a signal. 51 + */ 52 + asmlinkage int 53 + sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs) 54 + { 55 + sigset_t saveset; 56 + 57 + mask &= _BLOCKABLE; 58 + spin_lock_irq(&current->sighand->siglock); 59 + saveset = current->blocked; 60 + siginitset(&current->blocked, mask); 61 + recalc_sigpending(); 62 + spin_unlock_irq(&current->sighand->siglock); 63 + 64 + regs->r3 = -EINTR; 65 + while (1) { 66 + current->state = TASK_INTERRUPTIBLE; 67 + schedule(); 68 + if (do_signal(regs, &saveset, 1)) 69 + return -EINTR; 70 + } 71 + } 72 + 73 + asmlinkage int 74 + sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, 75 + struct pt_regs *regs) 76 + { 77 + sigset_t saveset, newset; 78 + 79 + /* XXX: Don't preclude handling different sized sigset_t's. */ 80 + if (sigsetsize != sizeof(sigset_t)) 81 + return -EINVAL; 82 + 83 + if (copy_from_user(&newset, unewset, sizeof(newset))) 84 + return -EFAULT; 85 + sigdelsetmask(&newset, ~_BLOCKABLE); 86 + spin_lock_irq(&current->sighand->siglock); 87 + saveset = current->blocked; 88 + current->blocked = newset; 89 + recalc_sigpending(); 90 + spin_unlock_irq(&current->sighand->siglock); 91 + 92 + regs->r3 = -EINTR; 93 + while (1) { 94 + current->state = TASK_INTERRUPTIBLE; 95 + schedule(); 96 + if (do_signal(regs, &saveset, 1)) 97 + return -EINTR; 98 + } 99 + } 100 + 101 + asmlinkage int 102 + sys_sigaction(int sig, const struct old_sigaction *act, 103 + struct old_sigaction *oact) 104 + { 105 + struct k_sigaction new_ka, old_ka; 106 + int ret; 107 + 108 + if (act) { 109 + old_sigset_t mask; 110 + if (!access_ok(VERIFY_READ, act, sizeof(*act)) || 111 + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || 112 + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) 113 + return -EFAULT; 114 + __get_user(new_ka.sa.sa_flags, &act->sa_flags); 115 + __get_user(mask, &act->sa_mask); 116 + siginitset(&new_ka.sa.sa_mask, mask); 117 + } 118 + 119 + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 120 + 121 + if (!ret && oact) { 122 + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || 123 + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || 124 + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) 125 + return -EFAULT; 126 + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); 127 + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); 128 + } 129 + 130 + return ret; 131 + } 132 + 133 + asmlinkage int 134 + sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, 135 + struct pt_regs *regs) 136 + { 137 + return do_sigaltstack(uss, uoss, regs->r1); 138 + } 139 + 140 + /* 141 + * Do a signal return; undo the signal stack. 142 + */ 143 + 144 + struct sigframe { 145 + struct sigcontext sc; 146 + unsigned long extramask[_NSIG_WORDS-1]; 147 + unsigned long tramp[2]; /* signal trampoline */ 148 + }; 149 + 150 + struct rt_sigframe { 151 + struct siginfo info; 152 + struct ucontext uc; 153 + unsigned long tramp[2]; /* signal trampoline */ 154 + }; 155 + 156 + static int 157 + restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p) 158 + { 159 + unsigned int err = 0; 160 + 161 + #define COPY(x) {err |= __get_user(regs->x, &sc->regs.x); } 162 + COPY(r0); 163 + COPY(r1); 164 + COPY(r2); COPY(r3); COPY(r4); COPY(r5); 165 + COPY(r6); COPY(r7); COPY(r8); COPY(r9); 166 + COPY(r10); COPY(r11); COPY(r12); COPY(r13); 167 + COPY(r14); COPY(r15); COPY(r16); COPY(r17); 168 + COPY(r18); COPY(r19); COPY(r20); COPY(r21); 169 + COPY(r22); COPY(r23); COPY(r24); COPY(r25); 170 + COPY(r26); COPY(r27); COPY(r28); COPY(r29); 171 + COPY(r30); COPY(r31); 172 + COPY(pc); COPY(ear); COPY(esr); COPY(fsr); 173 + #undef COPY 174 + 175 + *rval_p = regs->r3; 176 + 177 + return err; 178 + } 179 + 180 + asmlinkage int sys_sigreturn(struct pt_regs *regs) 181 + { 182 + struct sigframe *frame = (struct sigframe *)regs->r1; 183 + sigset_t set; 184 + int rval; 185 + 186 + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 187 + goto badframe; 188 + 189 + if (__get_user(set.sig[0], &frame->sc.oldmask) 190 + || (_NSIG_WORDS > 1 191 + && __copy_from_user(&set.sig[1], &frame->extramask, 192 + sizeof(frame->extramask)))) 193 + goto badframe; 194 + 195 + sigdelsetmask(&set, ~_BLOCKABLE); 196 + 197 + spin_lock_irq(&current->sighand->siglock); 198 + current->blocked = set; 199 + recalc_sigpending(); 200 + spin_unlock_irq(&current->sighand->siglock); 201 + 202 + if (restore_sigcontext(regs, &frame->sc, &rval)) 203 + goto badframe; 204 + return rval; 205 + 206 + badframe: 207 + force_sig(SIGSEGV, current); 208 + return 0; 209 + } 210 + 211 + asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) 212 + { 213 + struct rt_sigframe *frame = (struct rt_sigframe *)regs->r1; 214 + sigset_t set; 215 + stack_t st; 216 + int rval; 217 + 218 + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) 219 + goto badframe; 220 + 221 + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) 222 + goto badframe; 223 + 224 + sigdelsetmask(&set, ~_BLOCKABLE); 225 + spin_lock_irq(&current->sighand->siglock); 226 + current->blocked = set; 227 + recalc_sigpending(); 228 + spin_unlock_irq(&current->sighand->siglock); 229 + 230 + if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval)) 231 + goto badframe; 232 + 233 + if (__copy_from_user((void *)&st, &frame->uc.uc_stack, sizeof(st))) 234 + goto badframe; 235 + /* It is more difficult to avoid calling this function than to 236 + call it and ignore errors. */ 237 + do_sigaltstack(&st, NULL, regs->r1); 238 + 239 + return rval; 240 + 241 + badframe: 242 + force_sig(SIGSEGV, current); 243 + return 0; 244 + } 245 + 246 + /* 247 + * Set up a signal frame. 248 + */ 249 + 250 + static int 251 + setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, 252 + unsigned long mask) 253 + { 254 + int err = 0; 255 + 256 + #define COPY(x) {err |= __put_user(regs->x, &sc->regs.x); } 257 + COPY(r0); 258 + COPY(r1); 259 + COPY(r2); COPY(r3); COPY(r4); COPY(r5); 260 + COPY(r6); COPY(r7); COPY(r8); COPY(r9); 261 + COPY(r10); COPY(r11); COPY(r12); COPY(r13); 262 + COPY(r14); COPY(r15); COPY(r16); COPY(r17); 263 + COPY(r18); COPY(r19); COPY(r20); COPY(r21); 264 + COPY(r22); COPY(r23); COPY(r24); COPY(r25); 265 + COPY(r26); COPY(r27); COPY(r28); COPY(r29); 266 + COPY(r30); COPY(r31); 267 + COPY(pc); COPY(ear); COPY(esr); COPY(fsr); 268 + #undef COPY 269 + 270 + err |= __put_user(mask, &sc->oldmask); 271 + 272 + return err; 273 + } 274 + 275 + /* 276 + * Determine which stack to use.. 277 + */ 278 + static inline void * 279 + get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) 280 + { 281 + /* Default to using normal stack */ 282 + unsigned long sp = regs->r1; 283 + 284 + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp)) 285 + sp = current->sas_ss_sp + current->sas_ss_size; 286 + 287 + return (void *)((sp - frame_size) & -8UL); 288 + } 289 + 290 + static void setup_frame(int sig, struct k_sigaction *ka, 291 + sigset_t *set, struct pt_regs *regs) 292 + { 293 + struct sigframe *frame; 294 + int err = 0; 295 + int signal; 296 + 297 + frame = get_sigframe(ka, regs, sizeof(*frame)); 298 + 299 + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) 300 + goto give_sigsegv; 301 + 302 + signal = current_thread_info()->exec_domain 303 + && current_thread_info()->exec_domain->signal_invmap 304 + && sig < 32 305 + ? current_thread_info()->exec_domain->signal_invmap[sig] 306 + : sig; 307 + 308 + err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); 309 + 310 + if (_NSIG_WORDS > 1) { 311 + err |= __copy_to_user(frame->extramask, &set->sig[1], 312 + sizeof(frame->extramask)); 313 + } 314 + 315 + /* Set up to return from userspace. If provided, use a stub 316 + already in userspace. */ 317 + /* minus 8 is offset to cater for "rtsd r15,8" offset */ 318 + if (ka->sa.sa_flags & SA_RESTORER) { 319 + regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8; 320 + } else { 321 + /* Note, these encodings are _big endian_! */ 322 + 323 + /* addi r12, r0, __NR_sigreturn */ 324 + err |= __put_user(0x31800000 | __NR_sigreturn , 325 + frame->tramp + 0); 326 + /* brki r14, 0x8 */ 327 + err |= __put_user(0xb9cc0008, frame->tramp + 1); 328 + 329 + /* Return from sighandler will jump to the tramp. 330 + Negative 8 offset because return is rtsd r15, 8 */ 331 + regs->r15 = ((unsigned long)frame->tramp)-8; 332 + 333 + __invalidate_cache_sigtramp((unsigned long)frame->tramp); 334 + } 335 + 336 + if (err) 337 + goto give_sigsegv; 338 + 339 + /* Set up registers for signal handler */ 340 + regs->r1 = (unsigned long) frame; 341 + /* Signal handler args: */ 342 + regs->r5 = signal; /* Arg 0: signum */ 343 + regs->r6 = (unsigned long) &frame->sc; /* arg 1: sigcontext */ 344 + 345 + /* Offset of 4 to handle microblaze rtid r14, 0 */ 346 + regs->pc = (unsigned long)ka->sa.sa_handler; 347 + 348 + set_fs(USER_DS); 349 + 350 + #ifdef DEBUG_SIG 351 + printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n", 352 + current->comm, current->pid, frame, regs->pc); 353 + #endif 354 + 355 + return; 356 + 357 + give_sigsegv: 358 + if (sig == SIGSEGV) 359 + ka->sa.sa_handler = SIG_DFL; 360 + force_sig(SIGSEGV, current); 361 + } 362 + 363 + static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 364 + sigset_t *set, struct pt_regs *regs) 365 + { 366 + struct rt_sigframe *frame; 367 + int err = 0; 368 + int signal; 369 + 370 + frame = get_sigframe(ka, regs, sizeof(*frame)); 371 + 372 + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) 373 + goto give_sigsegv; 374 + 375 + signal = current_thread_info()->exec_domain 376 + && current_thread_info()->exec_domain->signal_invmap 377 + && sig < 32 378 + ? current_thread_info()->exec_domain->signal_invmap[sig] 379 + : sig; 380 + 381 + err |= copy_siginfo_to_user(&frame->info, info); 382 + 383 + /* Create the ucontext. */ 384 + err |= __put_user(0, &frame->uc.uc_flags); 385 + err |= __put_user(0, &frame->uc.uc_link); 386 + err |= __put_user((void *)current->sas_ss_sp, 387 + &frame->uc.uc_stack.ss_sp); 388 + err |= __put_user(sas_ss_flags(regs->r1), 389 + &frame->uc.uc_stack.ss_flags); 390 + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); 391 + err |= setup_sigcontext(&frame->uc.uc_mcontext, 392 + regs, set->sig[0]); 393 + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 394 + 395 + /* Set up to return from userspace. If provided, use a stub 396 + already in userspace. */ 397 + /* minus 8 is offset to cater for "rtsd r15,8" */ 398 + if (ka->sa.sa_flags & SA_RESTORER) { 399 + regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8; 400 + } else { 401 + /* addi r12, r0, __NR_sigreturn */ 402 + err |= __put_user(0x31800000 | __NR_rt_sigreturn , 403 + frame->tramp + 0); 404 + /* brki r14, 0x8 */ 405 + err |= __put_user(0xb9cc0008, frame->tramp + 1); 406 + 407 + /* Return from sighandler will jump to the tramp. 408 + Negative 8 offset because return is rtsd r15, 8 */ 409 + regs->r15 = ((unsigned long)frame->tramp)-8; 410 + 411 + __invalidate_cache_sigtramp((unsigned long)frame->tramp); 412 + } 413 + 414 + if (err) 415 + goto give_sigsegv; 416 + 417 + /* Set up registers for signal handler */ 418 + regs->r1 = (unsigned long) frame; 419 + /* Signal handler args: */ 420 + regs->r5 = signal; /* arg 0: signum */ 421 + regs->r6 = (unsigned long) &frame->info; /* arg 1: siginfo */ 422 + regs->r7 = (unsigned long) &frame->uc; /* arg2: ucontext */ 423 + /* Offset to handle microblaze rtid r14, 0 */ 424 + regs->pc = (unsigned long)ka->sa.sa_handler; 425 + 426 + set_fs(USER_DS); 427 + 428 + #ifdef DEBUG_SIG 429 + printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n", 430 + current->comm, current->pid, frame, regs->pc); 431 + #endif 432 + 433 + return; 434 + 435 + give_sigsegv: 436 + if (sig == SIGSEGV) 437 + ka->sa.sa_handler = SIG_DFL; 438 + force_sig(SIGSEGV, current); 439 + } 440 + 441 + /* Handle restarting system calls */ 442 + static inline void 443 + handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) 444 + { 445 + switch (regs->r3) { 446 + case -ERESTART_RESTARTBLOCK: 447 + case -ERESTARTNOHAND: 448 + if (!has_handler) 449 + goto do_restart; 450 + regs->r3 = -EINTR; 451 + break; 452 + case -ERESTARTSYS: 453 + if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { 454 + regs->r3 = -EINTR; 455 + break; 456 + } 457 + /* fallthrough */ 458 + case -ERESTARTNOINTR: 459 + do_restart: 460 + /* offset of 4 bytes to re-execute trap (brki) instruction */ 461 + regs->pc -= 4; 462 + break; 463 + } 464 + } 465 + 466 + /* 467 + * OK, we're invoking a handler 468 + */ 469 + 470 + static void 471 + handle_signal(unsigned long sig, struct k_sigaction *ka, 472 + siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) 473 + { 474 + /* Set up the stack frame */ 475 + if (ka->sa.sa_flags & SA_SIGINFO) 476 + setup_rt_frame(sig, ka, info, oldset, regs); 477 + else 478 + setup_frame(sig, ka, oldset, regs); 479 + 480 + if (ka->sa.sa_flags & SA_ONESHOT) 481 + ka->sa.sa_handler = SIG_DFL; 482 + 483 + if (!(ka->sa.sa_flags & SA_NODEFER)) { 484 + spin_lock_irq(&current->sighand->siglock); 485 + sigorsets(&current->blocked, 486 + &current->blocked, &ka->sa.sa_mask); 487 + sigaddset(&current->blocked, sig); 488 + recalc_sigpending(); 489 + spin_unlock_irq(&current->sighand->siglock); 490 + } 491 + } 492 + 493 + /* 494 + * Note that 'init' is a special process: it doesn't get signals it doesn't 495 + * want to handle. Thus you cannot kill init even with a SIGKILL even by 496 + * mistake. 497 + * 498 + * Note that we go through the signals twice: once to check the signals that 499 + * the kernel can handle, and then we build all the user-level signal handling 500 + * stack-frames in one go after that. 501 + */ 502 + int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) 503 + { 504 + siginfo_t info; 505 + int signr; 506 + struct k_sigaction ka; 507 + #ifdef DEBUG_SIG 508 + printk(KERN_INFO "do signal: %p %p %d\n", regs, oldset, in_syscall); 509 + printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1, 510 + regs->r12, current_thread_info()->flags); 511 + #endif 512 + /* 513 + * We want the common case to go fast, which 514 + * is why we may in certain cases get here from 515 + * kernel mode. Just return without doing anything 516 + * if so. 517 + */ 518 + if (kernel_mode(regs)) 519 + return 1; 520 + 521 + if (!oldset) 522 + oldset = &current->blocked; 523 + 524 + signr = get_signal_to_deliver(&info, &ka, regs, NULL); 525 + if (signr > 0) { 526 + /* Whee! Actually deliver the signal. */ 527 + if (in_syscall) 528 + handle_restart(regs, &ka, 1); 529 + handle_signal(signr, &ka, &info, oldset, regs); 530 + return 1; 531 + } 532 + 533 + if (in_syscall) 534 + handle_restart(regs, NULL, 0); 535 + 536 + /* Did we come from a system call? */ 537 + return 0; 538 + }