* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / arch / m68k / kernel / signal.c
blobf35dd94c521cf58e110c857da8a0d74ecc726a19
1 /*
2 * linux/arch/m68k/kernel/signal.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
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 */
12 * Linux/m68k support by Hamish Macdonald
14 * 68060 fixes by Jesper Skov
16 * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab
18 * mathemu support by Roman Zippel
19 * (Note: fpstate in the signal context is completly ignored for the emulator
20 * and the internal floating point format is put on stack)
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.
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
28 * signal handlers!
31 #include <linux/sched.h>
32 #include <linux/mm.h>
33 #include <linux/kernel.h>
34 #include <linux/signal.h>
35 #include <linux/errno.h>
36 #include <linux/wait.h>
37 #include <linux/ptrace.h>
38 #include <linux/unistd.h>
39 #include <linux/stddef.h>
41 #include <asm/setup.h>
42 #include <asm/uaccess.h>
43 #include <asm/pgtable.h>
44 #include <asm/traps.h>
45 #include <asm/ucontext.h>
47 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
49 asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
50 int options, unsigned long *ru);
51 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
53 const int frame_extra_sizes[16] = {
55 -1, /* sizeof(((struct frame *)0)->un.fmt1), */
56 sizeof(((struct frame *)0)->un.fmt2),
57 sizeof(((struct frame *)0)->un.fmt3),
58 sizeof(((struct frame *)0)->un.fmt4),
59 -1, /* sizeof(((struct frame *)0)->un.fmt5), */
60 -1, /* sizeof(((struct frame *)0)->un.fmt6), */
61 sizeof(((struct frame *)0)->un.fmt7),
62 -1, /* sizeof(((struct frame *)0)->un.fmt8), */
63 sizeof(((struct frame *)0)->un.fmt9),
64 sizeof(((struct frame *)0)->un.fmta),
65 sizeof(((struct frame *)0)->un.fmtb),
66 -1, /* sizeof(((struct frame *)0)->un.fmtc), */
67 -1, /* sizeof(((struct frame *)0)->un.fmtd), */
68 -1, /* sizeof(((struct frame *)0)->un.fmte), */
69 -1, /* sizeof(((struct frame *)0)->un.fmtf), */
73 * Atomically swap in the new signal mask, and wait for a signal.
75 asmlinkage int do_sigsuspend(struct pt_regs *regs)
77 old_sigset_t mask = regs->d3;
78 sigset_t saveset;
80 mask &= _BLOCKABLE;
81 saveset = current->blocked;
82 siginitset(&current->blocked, mask);
83 recalc_sigpending(current);
85 regs->d0 = -EINTR;
86 while (1) {
87 current->state = TASK_INTERRUPTIBLE;
88 schedule();
89 if (do_signal(&saveset, regs))
90 return -EINTR;
94 asmlinkage int
95 do_rt_sigsuspend(struct pt_regs *regs)
97 sigset_t *unewset = (sigset_t *)regs->d1;
98 size_t sigsetsize = (size_t)regs->d2;
99 sigset_t saveset, newset;
101 /* XXX: Don't preclude handling different sized sigset_t's. */
102 if (sigsetsize != sizeof(sigset_t))
103 return -EINVAL;
105 if (copy_from_user(&newset, unewset, sizeof(newset)))
106 return -EFAULT;
107 sigdelsetmask(&newset, ~_BLOCKABLE);
109 saveset = current->blocked;
110 current->blocked = newset;
111 recalc_sigpending(current);
113 regs->d0 = -EINTR;
114 while (1) {
115 current->state = TASK_INTERRUPTIBLE;
116 schedule();
117 if (do_signal(&saveset, regs))
118 return -EINTR;
122 asmlinkage int
123 sys_sigaction(int sig, const struct old_sigaction *act,
124 struct old_sigaction *oact)
126 struct k_sigaction new_ka, old_ka;
127 int ret;
129 if (act) {
130 old_sigset_t mask;
131 if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
132 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
133 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
134 return -EFAULT;
135 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
136 __get_user(mask, &act->sa_mask);
137 siginitset(&new_ka.sa.sa_mask, mask);
140 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
142 if (!ret && oact) {
143 if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
144 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
145 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
146 return -EFAULT;
147 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
148 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
151 return ret;
154 asmlinkage int
155 sys_sigaltstack(const stack_t *uss, stack_t *uoss)
157 return do_sigaltstack(uss, uoss, rdusp());
162 * Do a signal return; undo the signal stack.
164 * Keep the return code on the stack quadword aligned!
165 * That makes the cache flush below easier.
168 struct sigframe
170 char *pretcode;
171 int sig;
172 int code;
173 struct sigcontext *psc;
174 char retcode[8];
175 unsigned long extramask[_NSIG_WORDS-1];
176 struct sigcontext sc;
179 struct rt_sigframe
181 char *pretcode;
182 int sig;
183 struct siginfo *pinfo;
184 void *puc;
185 char retcode[8];
186 struct siginfo info;
187 struct ucontext uc;
191 static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */
193 static inline int restore_fpu_state(struct sigcontext *sc)
195 int err = 1;
197 if (FPU_IS_EMU) {
198 /* restore registers */
199 memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
200 memcpy(current->thread.fp, sc->sc_fpregs, 24);
201 return 0;
204 if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
205 /* Verify the frame format. */
206 if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
207 goto out;
208 if (CPU_IS_020_OR_030) {
209 if (m68k_fputype & FPU_68881 &&
210 !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
211 goto out;
212 if (m68k_fputype & FPU_68882 &&
213 !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
214 goto out;
215 } else if (CPU_IS_040) {
216 if (!(sc->sc_fpstate[1] == 0x00 ||
217 sc->sc_fpstate[1] == 0x28 ||
218 sc->sc_fpstate[1] == 0x60))
219 goto out;
220 } else if (CPU_IS_060) {
221 if (!(sc->sc_fpstate[3] == 0x00 ||
222 sc->sc_fpstate[3] == 0x60 ||
223 sc->sc_fpstate[3] == 0xe0))
224 goto out;
225 } else
226 goto out;
228 __asm__ volatile (".chip 68k/68881\n\t"
229 "fmovemx %0,%/fp0-%/fp1\n\t"
230 "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
231 ".chip 68k"
232 : /* no outputs */
233 : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
235 __asm__ volatile (".chip 68k/68881\n\t"
236 "frestore %0\n\t"
237 ".chip 68k" : : "m" (*sc->sc_fpstate));
238 err = 0;
240 out:
241 return err;
244 #define FPCONTEXT_SIZE 216
245 #define uc_fpstate uc_filler[0]
246 #define uc_formatvec uc_filler[FPCONTEXT_SIZE/4]
247 #define uc_extra uc_filler[FPCONTEXT_SIZE/4+1]
249 static inline int rt_restore_fpu_state(struct ucontext *uc)
251 unsigned char fpstate[FPCONTEXT_SIZE];
252 int context_size = CPU_IS_060 ? 8 : 0;
253 fpregset_t fpregs;
254 int err = 1;
256 if (FPU_IS_EMU) {
257 /* restore fpu control register */
258 if (__copy_from_user(current->thread.fpcntl,
259 &uc->uc_mcontext.fpregs.f_pcr, 12))
260 goto out;
261 /* restore all other fpu register */
262 if (__copy_from_user(current->thread.fp,
263 uc->uc_mcontext.fpregs.f_fpregs, 96))
264 goto out;
265 return 0;
268 if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate))
269 goto out;
270 if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
271 if (!CPU_IS_060)
272 context_size = fpstate[1];
273 /* Verify the frame format. */
274 if (!CPU_IS_060 && (fpstate[0] != fpu_version))
275 goto out;
276 if (CPU_IS_020_OR_030) {
277 if (m68k_fputype & FPU_68881 &&
278 !(context_size == 0x18 || context_size == 0xb4))
279 goto out;
280 if (m68k_fputype & FPU_68882 &&
281 !(context_size == 0x38 || context_size == 0xd4))
282 goto out;
283 } else if (CPU_IS_040) {
284 if (!(context_size == 0x00 ||
285 context_size == 0x28 ||
286 context_size == 0x60))
287 goto out;
288 } else if (CPU_IS_060) {
289 if (!(fpstate[3] == 0x00 ||
290 fpstate[3] == 0x60 ||
291 fpstate[3] == 0xe0))
292 goto out;
293 } else
294 goto out;
295 if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
296 sizeof(fpregs)))
297 goto out;
298 __asm__ volatile (".chip 68k/68881\n\t"
299 "fmovemx %0,%/fp0-%/fp7\n\t"
300 "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
301 ".chip 68k"
302 : /* no outputs */
303 : "m" (*fpregs.f_fpregs),
304 "m" (fpregs.f_pcr));
306 if (context_size &&
307 __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1,
308 context_size))
309 goto out;
310 __asm__ volatile (".chip 68k/68881\n\t"
311 "frestore %0\n\t"
312 ".chip 68k" : : "m" (*fpstate));
313 err = 0;
315 out:
316 return err;
319 static inline int
320 restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp,
321 int *pd0)
323 int fsize, formatvec;
324 struct sigcontext context;
325 int err;
327 /* get previous context */
328 if (copy_from_user(&context, usc, sizeof(context)))
329 goto badframe;
331 /* restore passed registers */
332 regs->d1 = context.sc_d1;
333 regs->a0 = context.sc_a0;
334 regs->a1 = context.sc_a1;
335 regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
336 regs->pc = context.sc_pc;
337 regs->orig_d0 = -1; /* disable syscall checks */
338 wrusp(context.sc_usp);
339 formatvec = context.sc_formatvec;
340 regs->format = formatvec >> 12;
341 regs->vector = formatvec & 0xfff;
343 err = restore_fpu_state(&context);
345 fsize = frame_extra_sizes[regs->format];
346 if (fsize < 0) {
348 * user process trying to return with weird frame format
350 #if DEBUG
351 printk("user process returning with weird frame format\n");
352 #endif
353 goto badframe;
356 /* OK. Make room on the supervisor stack for the extra junk,
357 * if necessary.
360 if (fsize) {
361 struct switch_stack *sw = (struct switch_stack *)regs - 1;
362 regs->d0 = context.sc_d0;
363 #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
364 __asm__ __volatile__
365 (" movel %0,%/a0\n\t"
366 " subl %1,%/a0\n\t" /* make room on stack */
367 " movel %/a0,%/sp\n\t" /* set stack pointer */
368 /* move switch_stack and pt_regs */
369 "1: movel %0@+,%/a0@+\n\t"
370 " dbra %2,1b\n\t"
371 " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
372 " lsrl #2,%1\n\t"
373 " subql #1,%1\n\t"
374 "2: movesl %4@+,%2\n\t"
375 "3: movel %2,%/a0@+\n\t"
376 " dbra %1,2b\n\t"
377 " bral " SYMBOL_NAME_STR(ret_from_signal) "\n"
378 "4:\n"
379 ".section __ex_table,\"a\"\n"
380 " .align 4\n"
381 " .long 2b,4b\n"
382 " .long 3b,4b\n"
383 ".previous"
384 : /* no outputs, it doesn't ever return */
385 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
386 "n" (frame_offset), "a" (fp)
387 : "a0");
388 #undef frame_offset
390 * If we ever get here an exception occurred while
391 * building the above stack-frame.
393 goto badframe;
396 *pd0 = context.sc_d0;
397 return err;
399 badframe:
400 return 1;
403 static inline int
404 rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
405 struct ucontext *uc, int *pd0)
407 int fsize, temp;
408 greg_t *gregs = uc->uc_mcontext.gregs;
409 unsigned long usp;
410 int err;
412 err = __get_user(temp, &uc->uc_mcontext.version);
413 if (temp != MCONTEXT_VERSION)
414 goto badframe;
415 /* restore passed registers */
416 err |= __get_user(regs->d0, &gregs[0]);
417 err |= __get_user(regs->d1, &gregs[1]);
418 err |= __get_user(regs->d2, &gregs[2]);
419 err |= __get_user(regs->d3, &gregs[3]);
420 err |= __get_user(regs->d4, &gregs[4]);
421 err |= __get_user(regs->d5, &gregs[5]);
422 err |= __get_user(sw->d6, &gregs[6]);
423 err |= __get_user(sw->d7, &gregs[7]);
424 err |= __get_user(regs->a0, &gregs[8]);
425 err |= __get_user(regs->a1, &gregs[9]);
426 err |= __get_user(regs->a2, &gregs[10]);
427 err |= __get_user(sw->a3, &gregs[11]);
428 err |= __get_user(sw->a4, &gregs[12]);
429 err |= __get_user(sw->a5, &gregs[13]);
430 err |= __get_user(sw->a6, &gregs[14]);
431 err |= __get_user(usp, &gregs[15]);
432 wrusp(usp);
433 err |= __get_user(regs->pc, &gregs[16]);
434 err |= __get_user(temp, &gregs[17]);
435 regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
436 regs->orig_d0 = -1; /* disable syscall checks */
437 err |= __get_user(temp, &uc->uc_formatvec);
438 regs->format = temp >> 12;
439 regs->vector = temp & 0xfff;
441 err |= rt_restore_fpu_state(uc);
443 if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
444 goto badframe;
446 fsize = frame_extra_sizes[regs->format];
447 if (fsize < 0) {
449 * user process trying to return with weird frame format
451 #if DEBUG
452 printk("user process returning with weird frame format\n");
453 #endif
454 goto badframe;
457 /* OK. Make room on the supervisor stack for the extra junk,
458 * if necessary.
461 if (fsize) {
462 #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
463 __asm__ __volatile__
464 (" movel %0,%/a0\n\t"
465 " subl %1,%/a0\n\t" /* make room on stack */
466 " movel %/a0,%/sp\n\t" /* set stack pointer */
467 /* move switch_stack and pt_regs */
468 "1: movel %0@+,%/a0@+\n\t"
469 " dbra %2,1b\n\t"
470 " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
471 " lsrl #2,%1\n\t"
472 " subql #1,%1\n\t"
473 "2: movesl %4@+,%2\n\t"
474 "3: movel %2,%/a0@+\n\t"
475 " dbra %1,2b\n\t"
476 " bral " SYMBOL_NAME_STR(ret_from_signal) "\n"
477 "4:\n"
478 ".section __ex_table,\"a\"\n"
479 " .align 4\n"
480 " .long 2b,4b\n"
481 " .long 3b,4b\n"
482 ".previous"
483 : /* no outputs, it doesn't ever return */
484 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
485 "n" (frame_offset), "a" (&uc->uc_extra)
486 : "a0");
487 #undef frame_offset
489 * If we ever get here an exception occurred while
490 * building the above stack-frame.
492 goto badframe;
495 *pd0 = regs->d0;
496 return err;
498 badframe:
499 return 1;
502 asmlinkage int do_sigreturn(unsigned long __unused)
504 struct switch_stack *sw = (struct switch_stack *) &__unused;
505 struct pt_regs *regs = (struct pt_regs *) (sw + 1);
506 unsigned long usp = rdusp();
507 struct sigframe *frame = (struct sigframe *)(usp - 4);
508 sigset_t set;
509 int d0;
511 if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
512 goto badframe;
513 if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
514 (_NSIG_WORDS > 1 &&
515 __copy_from_user(&set.sig[1], &frame->extramask,
516 sizeof(frame->extramask))))
517 goto badframe;
519 sigdelsetmask(&set, ~_BLOCKABLE);
520 current->blocked = set;
521 recalc_sigpending(current);
523 if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
524 goto badframe;
525 return d0;
527 badframe:
528 force_sig(SIGSEGV, current);
529 return 0;
532 asmlinkage int do_rt_sigreturn(unsigned long __unused)
534 struct switch_stack *sw = (struct switch_stack *) &__unused;
535 struct pt_regs *regs = (struct pt_regs *) (sw + 1);
536 unsigned long usp = rdusp();
537 struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
538 sigset_t set;
539 int d0;
541 if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
542 goto badframe;
543 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
544 goto badframe;
546 sigdelsetmask(&set, ~_BLOCKABLE);
547 current->blocked = set;
548 recalc_sigpending(current);
550 if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
551 goto badframe;
552 return d0;
554 badframe:
555 force_sig(SIGSEGV, current);
556 return 0;
560 * Set up a signal frame.
563 static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
565 if (FPU_IS_EMU) {
566 /* save registers */
567 memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
568 memcpy(sc->sc_fpregs, current->thread.fp, 24);
569 return;
572 __asm__ volatile (".chip 68k/68881\n\t"
573 "fsave %0\n\t"
574 ".chip 68k"
575 : : "m" (*sc->sc_fpstate) : "memory");
577 if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
578 fpu_version = sc->sc_fpstate[0];
579 if (CPU_IS_020_OR_030 &&
580 regs->vector >= (VEC_FPBRUC * 4) &&
581 regs->vector <= (VEC_FPNAN * 4)) {
582 /* Clear pending exception in 68882 idle frame */
583 if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
584 sc->sc_fpstate[0x38] |= 1 << 3;
586 __asm__ volatile (".chip 68k/68881\n\t"
587 "fmovemx %/fp0-%/fp1,%0\n\t"
588 "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t"
589 ".chip 68k"
590 : /* no outputs */
591 : "m" (*sc->sc_fpregs),
592 "m" (*sc->sc_fpcntl)
593 : "memory");
597 static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
599 unsigned char fpstate[FPCONTEXT_SIZE];
600 int context_size = CPU_IS_060 ? 8 : 0;
601 int err = 0;
603 if (FPU_IS_EMU) {
604 /* save fpu control register */
605 err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr,
606 current->thread.fpcntl, 12);
607 /* save all other fpu register */
608 err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
609 current->thread.fp, 96);
610 return err;
613 __asm__ volatile (".chip 68k/68881\n\t"
614 "fsave %0\n\t"
615 ".chip 68k"
616 : : "m" (*fpstate) : "memory");
618 err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
619 if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
620 fpregset_t fpregs;
621 if (!CPU_IS_060)
622 context_size = fpstate[1];
623 fpu_version = fpstate[0];
624 if (CPU_IS_020_OR_030 &&
625 regs->vector >= (VEC_FPBRUC * 4) &&
626 regs->vector <= (VEC_FPNAN * 4)) {
627 /* Clear pending exception in 68882 idle frame */
628 if (*(unsigned short *) fpstate == 0x1f38)
629 fpstate[0x38] |= 1 << 3;
631 __asm__ volatile (".chip 68k/68881\n\t"
632 "fmovemx %/fp0-%/fp7,%0\n\t"
633 "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t"
634 ".chip 68k"
635 : /* no outputs */
636 : "m" (*fpregs.f_fpregs),
637 "m" (fpregs.f_pcr)
638 : "memory");
639 err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
640 sizeof(fpregs));
642 if (context_size)
643 err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
644 context_size);
645 return err;
648 static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
649 unsigned long mask)
651 sc->sc_mask = mask;
652 sc->sc_usp = rdusp();
653 sc->sc_d0 = regs->d0;
654 sc->sc_d1 = regs->d1;
655 sc->sc_a0 = regs->a0;
656 sc->sc_a1 = regs->a1;
657 sc->sc_sr = regs->sr;
658 sc->sc_pc = regs->pc;
659 sc->sc_formatvec = regs->format << 12 | regs->vector;
660 save_fpu_state(sc, regs);
663 static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
665 struct switch_stack *sw = (struct switch_stack *)regs - 1;
666 greg_t *gregs = uc->uc_mcontext.gregs;
667 int err = 0;
669 err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
670 err |= __put_user(regs->d0, &gregs[0]);
671 err |= __put_user(regs->d1, &gregs[1]);
672 err |= __put_user(regs->d2, &gregs[2]);
673 err |= __put_user(regs->d3, &gregs[3]);
674 err |= __put_user(regs->d4, &gregs[4]);
675 err |= __put_user(regs->d5, &gregs[5]);
676 err |= __put_user(sw->d6, &gregs[6]);
677 err |= __put_user(sw->d7, &gregs[7]);
678 err |= __put_user(regs->a0, &gregs[8]);
679 err |= __put_user(regs->a1, &gregs[9]);
680 err |= __put_user(regs->a2, &gregs[10]);
681 err |= __put_user(sw->a3, &gregs[11]);
682 err |= __put_user(sw->a4, &gregs[12]);
683 err |= __put_user(sw->a5, &gregs[13]);
684 err |= __put_user(sw->a6, &gregs[14]);
685 err |= __put_user(rdusp(), &gregs[15]);
686 err |= __put_user(regs->pc, &gregs[16]);
687 err |= __put_user(regs->sr, &gregs[17]);
688 err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
689 err |= rt_save_fpu_state(uc, regs);
690 return err;
693 static inline void push_cache (unsigned long vaddr)
696 * Using the old cache_push_v() was really a big waste.
698 * What we are trying to do is to flush 8 bytes to ram.
699 * Flushing 2 cache lines of 16 bytes is much cheaper than
700 * flushing 1 or 2 pages, as previously done in
701 * cache_push_v().
702 * Jes
704 if (CPU_IS_040) {
705 unsigned long temp;
707 __asm__ __volatile__ (".chip 68040\n\t"
708 "nop\n\t"
709 "ptestr (%1)\n\t"
710 "movec %%mmusr,%0\n\t"
711 ".chip 68k"
712 : "=r" (temp)
713 : "a" (vaddr));
715 temp &= PAGE_MASK;
716 temp |= vaddr & ~PAGE_MASK;
718 __asm__ __volatile__ (".chip 68040\n\t"
719 "nop\n\t"
720 "cpushl %%bc,(%0)\n\t"
721 ".chip 68k"
722 : : "a" (temp));
724 else if (CPU_IS_060) {
725 unsigned long temp;
726 __asm__ __volatile__ (".chip 68060\n\t"
727 "plpar (%0)\n\t"
728 ".chip 68k"
729 : "=a" (temp)
730 : "0" (vaddr));
731 __asm__ __volatile__ (".chip 68060\n\t"
732 "cpushl %%bc,(%0)\n\t"
733 ".chip 68k"
734 : : "a" (temp));
736 else {
738 * 68030/68020 have no writeback cache;
739 * still need to clear icache.
740 * Note that vaddr is guaranteed to be long word aligned.
742 unsigned long temp;
743 asm volatile ("movec %%cacr,%0" : "=r" (temp));
744 temp += 4;
745 asm volatile ("movec %0,%%caar\n\t"
746 "movec %1,%%cacr"
747 : : "r" (vaddr), "r" (temp));
748 asm volatile ("movec %0,%%caar\n\t"
749 "movec %1,%%cacr"
750 : : "r" (vaddr + 4), "r" (temp));
754 static inline void *
755 get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
757 unsigned long usp;
759 /* Default to using normal stack. */
760 usp = rdusp();
762 /* This is the X/Open sanctioned signal stack switching. */
763 if (ka->sa.sa_flags & SA_ONSTACK) {
764 if (!on_sig_stack(usp))
765 usp = current->sas_ss_sp + current->sas_ss_size;
767 return (void *)((usp - frame_size) & -8UL);
770 static void setup_frame (int sig, struct k_sigaction *ka,
771 sigset_t *set, struct pt_regs *regs)
773 struct sigframe *frame;
774 int fsize = frame_extra_sizes[regs->format];
775 struct sigcontext context;
776 int err = 0;
778 if (fsize < 0) {
779 #ifdef DEBUG
780 printk ("setup_frame: Unknown frame format %#x\n",
781 regs->format);
782 #endif
783 goto give_sigsegv;
786 frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);
788 if (fsize) {
789 err |= copy_to_user (frame + 1, regs + 1, fsize);
790 regs->stkadj = fsize;
793 err |= __put_user((current->exec_domain
794 && current->exec_domain->signal_invmap
795 && sig < 32
796 ? current->exec_domain->signal_invmap[sig]
797 : sig),
798 &frame->sig);
800 err |= __put_user(regs->vector, &frame->code);
801 err |= __put_user(&frame->sc, &frame->psc);
803 if (_NSIG_WORDS > 1)
804 err |= copy_to_user(frame->extramask, &set->sig[1],
805 sizeof(frame->extramask));
807 setup_sigcontext(&context, regs, set->sig[0]);
808 err |= copy_to_user (&frame->sc, &context, sizeof(context));
810 /* Set up to return from userspace. */
811 err |= __put_user(frame->retcode, &frame->pretcode);
812 /* moveq #,d0; trap #0 */
813 err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
814 (long *)(frame->retcode));
816 if (err)
817 goto give_sigsegv;
819 push_cache ((unsigned long) &frame->retcode);
821 /* Set up registers for signal handler */
822 wrusp ((unsigned long) frame);
823 regs->pc = (unsigned long) ka->sa.sa_handler;
825 adjust_stack:
826 /* Prepare to skip over the extra stuff in the exception frame. */
827 if (regs->stkadj) {
828 struct pt_regs *tregs =
829 (struct pt_regs *)((ulong)regs + regs->stkadj);
830 #if DEBUG
831 printk("Performing stackadjust=%04x\n", regs->stkadj);
832 #endif
833 /* This must be copied with decreasing addresses to
834 handle overlaps. */
835 tregs->vector = 0;
836 tregs->format = 0;
837 tregs->pc = regs->pc;
838 tregs->sr = regs->sr;
840 return;
842 give_sigsegv:
843 if (sig == SIGSEGV)
844 ka->sa.sa_handler = SIG_DFL;
845 force_sig(SIGSEGV, current);
846 goto adjust_stack;
849 static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
850 sigset_t *set, struct pt_regs *regs)
852 struct rt_sigframe *frame;
853 int fsize = frame_extra_sizes[regs->format];
854 int err = 0;
856 if (fsize < 0) {
857 #ifdef DEBUG
858 printk ("setup_frame: Unknown frame format %#x\n",
859 regs->format);
860 #endif
861 goto give_sigsegv;
864 frame = get_sigframe(ka, regs, sizeof(*frame));
866 if (fsize) {
867 err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
868 regs->stkadj = fsize;
871 err |= __put_user((current->exec_domain
872 && current->exec_domain->signal_invmap
873 && sig < 32
874 ? current->exec_domain->signal_invmap[sig]
875 : sig),
876 &frame->sig);
877 err |= __put_user(&frame->info, &frame->pinfo);
878 err |= __put_user(&frame->uc, &frame->puc);
879 err |= __copy_to_user(&frame->info, info, sizeof(*info));
881 /* Create the ucontext. */
882 err |= __put_user(0, &frame->uc.uc_flags);
883 err |= __put_user(0, &frame->uc.uc_link);
884 err |= __put_user((void *)current->sas_ss_sp,
885 &frame->uc.uc_stack.ss_sp);
886 err |= __put_user(sas_ss_flags(rdusp()),
887 &frame->uc.uc_stack.ss_flags);
888 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
889 err |= rt_setup_ucontext(&frame->uc, regs);
890 err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
892 /* Set up to return from userspace. */
893 err |= __put_user(frame->retcode, &frame->pretcode);
894 /* moveq #,d0; notb d0; trap #0 */
895 err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
896 (long *)(frame->retcode + 0));
897 err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
899 if (err)
900 goto give_sigsegv;
902 push_cache ((unsigned long) &frame->retcode);
904 /* Set up registers for signal handler */
905 wrusp ((unsigned long) frame);
906 regs->pc = (unsigned long) ka->sa.sa_handler;
908 adjust_stack:
909 /* Prepare to skip over the extra stuff in the exception frame. */
910 if (regs->stkadj) {
911 struct pt_regs *tregs =
912 (struct pt_regs *)((ulong)regs + regs->stkadj);
913 #if DEBUG
914 printk("Performing stackadjust=%04x\n", regs->stkadj);
915 #endif
916 /* This must be copied with decreasing addresses to
917 handle overlaps. */
918 tregs->vector = 0;
919 tregs->format = 0;
920 tregs->pc = regs->pc;
921 tregs->sr = regs->sr;
923 return;
925 give_sigsegv:
926 if (sig == SIGSEGV)
927 ka->sa.sa_handler = SIG_DFL;
928 force_sig(SIGSEGV, current);
929 goto adjust_stack;
932 static inline void
933 handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
935 switch (regs->d0) {
936 case -ERESTARTNOHAND:
937 if (!has_handler)
938 goto do_restart;
939 regs->d0 = -EINTR;
940 break;
942 case -ERESTARTSYS:
943 if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
944 regs->d0 = -EINTR;
945 break;
947 /* fallthrough */
948 case -ERESTARTNOINTR:
949 do_restart:
950 regs->d0 = regs->orig_d0;
951 regs->pc -= 2;
952 break;
957 * OK, we're invoking a handler
959 static void
960 handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
961 sigset_t *oldset, struct pt_regs *regs)
963 /* are we from a system call? */
964 if (regs->orig_d0 >= 0)
965 /* If so, check system call restarting.. */
966 handle_restart(regs, ka, 1);
968 /* set up the stack frame */
969 if (ka->sa.sa_flags & SA_SIGINFO)
970 setup_rt_frame(sig, ka, info, oldset, regs);
971 else
972 setup_frame(sig, ka, oldset, regs);
974 if (ka->sa.sa_flags & SA_ONESHOT)
975 ka->sa.sa_handler = SIG_DFL;
977 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
978 if (!(ka->sa.sa_flags & SA_NODEFER))
979 sigaddset(&current->blocked,sig);
980 recalc_sigpending(current);
984 * Note that 'init' is a special process: it doesn't get signals it doesn't
985 * want to handle. Thus you cannot kill init even with a SIGKILL even by
986 * mistake.
988 * Note that we go through the signals twice: once to check the signals
989 * that the kernel can handle, and then we build all the user-level signal
990 * handling stack-frames in one go after that.
992 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
994 siginfo_t info;
995 struct k_sigaction *ka;
997 current->thread.esp0 = (unsigned long) regs;
999 if (!oldset)
1000 oldset = &current->blocked;
1002 for (;;) {
1003 int signr;
1005 signr = dequeue_signal(&current->blocked, &info);
1007 if (!signr)
1008 break;
1010 if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
1011 current->exit_code = signr;
1012 current->state = TASK_STOPPED;
1013 regs->sr &= ~PS_T;
1015 /* Did we come from a system call? */
1016 if (regs->orig_d0 >= 0) {
1017 /* Restart the system call the same way as
1018 if the process were not traced. */
1019 struct k_sigaction *ka =
1020 &current->sig->action[signr-1];
1021 int has_handler =
1022 (ka->sa.sa_handler != SIG_IGN &&
1023 ka->sa.sa_handler != SIG_DFL);
1024 handle_restart(regs, ka, has_handler);
1026 notify_parent(current, SIGCHLD);
1027 schedule();
1029 /* We're back. Did the debugger cancel the sig? */
1030 if (!(signr = current->exit_code)) {
1031 discard_frame:
1032 /* Make sure that a faulted bus cycle isn't
1033 restarted (only needed on the 680[23]0). */
1034 if (regs->format == 10 || regs->format == 11)
1035 regs->stkadj = frame_extra_sizes[regs->format];
1036 continue;
1038 current->exit_code = 0;
1040 /* The debugger continued. Ignore SIGSTOP. */
1041 if (signr == SIGSTOP)
1042 goto discard_frame;
1044 /* Update the siginfo structure. Is this good? */
1045 if (signr != info.si_signo) {
1046 info.si_signo = signr;
1047 info.si_errno = 0;
1048 info.si_code = SI_USER;
1049 info.si_pid = current->p_pptr->pid;
1050 info.si_uid = current->p_pptr->uid;
1053 /* If the (new) signal is now blocked, requeue it. */
1054 if (sigismember(&current->blocked, signr)) {
1055 send_sig_info(signr, &info, current);
1056 continue;
1060 ka = &current->sig->action[signr-1];
1061 if (ka->sa.sa_handler == SIG_IGN) {
1062 if (signr != SIGCHLD)
1063 continue;
1064 /* Check for SIGCHLD: it's special. */
1065 while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
1066 /* nothing */;
1067 continue;
1070 if (ka->sa.sa_handler == SIG_DFL) {
1071 int exit_code = signr;
1073 if (current->pid == 1)
1074 continue;
1076 switch (signr) {
1077 case SIGCONT: case SIGCHLD: case SIGWINCH:
1078 continue;
1080 case SIGTSTP: case SIGTTIN: case SIGTTOU:
1081 if (is_orphaned_pgrp(current->pgrp))
1082 continue;
1083 /* FALLTHRU */
1085 case SIGSTOP:
1086 current->state = TASK_STOPPED;
1087 current->exit_code = signr;
1088 if (!(current->p_pptr->sig->action[SIGCHLD-1]
1089 .sa.sa_flags & SA_NOCLDSTOP))
1090 notify_parent(current, SIGCHLD);
1091 schedule();
1092 continue;
1094 case SIGQUIT: case SIGILL: case SIGTRAP:
1095 case SIGIOT: case SIGFPE: case SIGSEGV:
1096 if (do_coredump(signr, regs))
1097 exit_code |= 0x80;
1098 /* FALLTHRU */
1100 default:
1101 sigaddset(&current->signal, signr);
1102 recalc_sigpending(current);
1103 current->flags |= PF_SIGNALED;
1104 do_exit(exit_code);
1105 /* NOTREACHED */
1109 /* Whee! Actually deliver the signal. */
1110 handle_signal(signr, ka, &info, oldset, regs);
1111 return 1;
1114 /* Did we come from a system call? */
1115 if (regs->orig_d0 >= 0)
1116 /* Restart the system call - no handlers present */
1117 handle_restart(regs, NULL, 0);
1119 /* If we are about to discard some frame stuff we must copy
1120 over the remaining frame. */
1121 if (regs->stkadj) {
1122 struct pt_regs *tregs =
1123 (struct pt_regs *) ((ulong) regs + regs->stkadj);
1125 /* This must be copied with decreasing addresses to
1126 handle overlaps. */
1127 tregs->vector = 0;
1128 tregs->format = 0;
1129 tregs->pc = regs->pc;
1130 tregs->sr = regs->sr;
1132 return 0;