Root/target/linux/coldfire/files-2.6.31/arch/m68k/coldfire/common/signal.c

1/*
2 * linux/arch/m68k/kernel/signal.c
3 *
4 * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
5 * Matt Waddel Matt.Waddel@freescale.com
6 * Jason Jin Jason.Jin@freescale.com
7 * Shrek Wu B16972@freescale.com
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive
11 * for more details.
12 *
13 * Derived from m68k/kernel/signal.c and the original authors are credited
14 * there.
15 */
16
17#include <linux/sched.h>
18#include <linux/mm.h>
19#include <linux/kernel.h>
20#include <linux/signal.h>
21#include <linux/syscalls.h>
22#include <linux/errno.h>
23#include <linux/wait.h>
24#include <linux/ptrace.h>
25#include <linux/unistd.h>
26#include <linux/stddef.h>
27#include <linux/highuid.h>
28#include <linux/personality.h>
29#include <linux/tty.h>
30#include <linux/binfmts.h>
31
32#include <asm/setup.h>
33#include <asm/cf_uaccess.h>
34#include <asm/cf_pgtable.h>
35#include <asm/traps.h>
36#include <asm/ucontext.h>
37#include <asm/cacheflush.h>
38
39#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
40
41asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
42
43const int frame_extra_sizes[16] = {
44  [1] = -1,
45  [2] = sizeof(((struct frame *)0)->un.fmt2),
46  [3] = sizeof(((struct frame *)0)->un.fmt3),
47  [4] = 0,
48  [5] = -1,
49  [6] = -1,
50  [7] = sizeof(((struct frame *)0)->un.fmt7),
51  [8] = -1,
52  [9] = sizeof(((struct frame *)0)->un.fmt9),
53  [10] = sizeof(((struct frame *)0)->un.fmta),
54  [11] = sizeof(((struct frame *)0)->un.fmtb),
55  [12] = -1,
56  [13] = -1,
57  [14] = -1,
58  [15] = -1,
59};
60
61/*
62 * Atomically swap in the new signal mask, and wait for a signal.
63 */
64asmlinkage int do_sigsuspend(struct pt_regs *regs)
65{
66    old_sigset_t mask = regs->d3;
67    sigset_t saveset;
68
69    mask &= _BLOCKABLE;
70    spin_lock_irq(&current->sighand->siglock);
71    saveset = current->blocked;
72    siginitset(&current->blocked, mask);
73    recalc_sigpending();
74    spin_unlock_irq(&current->sighand->siglock);
75
76    regs->d0 = -EINTR;
77    while (1) {
78        current->state = TASK_INTERRUPTIBLE;
79        schedule();
80        if (do_signal(&saveset, regs))
81            return -EINTR;
82    }
83}
84
85asmlinkage int
86do_rt_sigsuspend(struct pt_regs *regs)
87{
88    sigset_t __user *unewset = (sigset_t __user *)regs->d1;
89    size_t sigsetsize = (size_t)regs->d2;
90    sigset_t saveset, newset;
91
92    /* XXX: Don't preclude handling different sized sigset_t's. */
93    if (sigsetsize != sizeof(sigset_t))
94        return -EINVAL;
95
96    if (copy_from_user(&newset, unewset, sizeof(newset)))
97        return -EFAULT;
98    sigdelsetmask(&newset, ~_BLOCKABLE);
99
100    spin_lock_irq(&current->sighand->siglock);
101    saveset = current->blocked;
102    current->blocked = newset;
103    recalc_sigpending();
104    spin_unlock_irq(&current->sighand->siglock);
105
106    regs->d0 = -EINTR;
107    while (1) {
108        current->state = TASK_INTERRUPTIBLE;
109        schedule();
110        if (do_signal(&saveset, regs))
111            return -EINTR;
112    }
113}
114
115asmlinkage int
116sys_sigaction(int sig, const struct old_sigaction __user *act,
117          struct old_sigaction __user *oact)
118{
119    struct k_sigaction new_ka, old_ka;
120    int ret;
121
122    if (act) {
123        old_sigset_t mask;
124        if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
125            __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
126            __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
127            return -EFAULT;
128        __get_user(new_ka.sa.sa_flags, &act->sa_flags);
129        __get_user(mask, &act->sa_mask);
130        siginitset(&new_ka.sa.sa_mask, mask);
131    }
132
133    ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
134
135    if (!ret && oact) {
136        if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
137            __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
138            __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
139            return -EFAULT;
140        __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
141        __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
142    }
143
144    return ret;
145}
146
147asmlinkage int
148sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
149{
150    return do_sigaltstack(uss, uoss, rdusp());
151}
152
153
154/*
155 * Do a signal return; undo the signal stack.
156 *
157 * Keep the return code on the stack quadword aligned!
158 * That makes the cache flush below easier.
159 */
160
161struct sigframe
162{
163    char __user *pretcode;
164    int sig;
165    int code;
166    struct sigcontext __user *psc;
167    char retcode[8];
168    unsigned long extramask[_NSIG_WORDS-1];
169    struct sigcontext sc;
170};
171
172struct rt_sigframe
173{
174    char __user *pretcode;
175    int sig;
176    struct siginfo __user *pinfo;
177    void __user *puc;
178    char retcode[8];
179    struct siginfo info;
180    struct ucontext uc;
181};
182
183#define FPCONTEXT_SIZE 216
184#define uc_fpstate uc_filler[0]
185#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4]
186#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1]
187
188#ifdef CONFIG_FPU
189static unsigned char fpu_version; /* version num of fpu, set by setup_frame */
190
191static inline int restore_fpu_state(struct sigcontext *sc)
192{
193    int err = 1;
194
195    if (FPU_IS_EMU) {
196        /* restore registers */
197        memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
198        memcpy(current->thread.fp, sc->sc_fpregs, 24);
199        return 0;
200    }
201
202    if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
203        /* Verify the frame format. */
204        if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
205        goto out;
206        if (CPU_IS_020_OR_030) {
207        if (m68k_fputype & FPU_68881 &&
208            !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
209            goto out;
210        if (m68k_fputype & FPU_68882 &&
211            !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
212            goto out;
213        } else if (CPU_IS_040) {
214        if (!(sc->sc_fpstate[1] == 0x00 ||
215              sc->sc_fpstate[1] == 0x28 ||
216              sc->sc_fpstate[1] == 0x60))
217            goto out;
218        } else if (CPU_IS_060) {
219        if (!(sc->sc_fpstate[3] == 0x00 ||
220              sc->sc_fpstate[3] == 0x60 ||
221              sc->sc_fpstate[3] == 0xe0))
222            goto out;
223        } else if (CPU_IS_CFV4E) {
224        pr_debug("restore v4e fpu state at %s\n", __func__);
225        } else
226        goto out;
227#ifdef CONFIG_CFV4E
228        __asm__ volatile ("fmovem %0,%/fp0-%/fp1\n\t"
229                  QCHIP_RESTORE_DIRECTIVE
230                  : /* no outputs */
231                  : "m" (sc->sc_fpregs[0][0])
232                  : "memory");
233        __asm__ volatile ("fmovel %0,%/fpcr"
234                  : : "m" (sc->sc_fpcntl[0])
235                  : "memory" );
236        __asm__ volatile ("fmovel %0,%/fpsr"
237                  : : "m" (sc->sc_fpcntl[1])
238                  : "memory" );
239        __asm__ volatile ("fmovel %0,%/fpiar"
240                  : : "m" (sc->sc_fpcntl[2])
241                  : "memory" );
242
243#endif
244    }
245
246#ifdef CONFIG_CFV4E
247        __asm__ volatile ("frestore %0\n\t"
248                          QCHIP_RESTORE_DIRECTIVE : : "m" (*sc->sc_fpstate));
249#endif
250    err = 0;
251
252out:
253    return err;
254}
255
256static inline int rt_restore_fpu_state(struct ucontext __user *uc)
257{
258    unsigned char fpstate[FPCONTEXT_SIZE];
259    int context_size = CPU_IS_060 ? 8 : 0;
260    fpregset_t fpregs;
261    int err = 1;
262
263    if (FPU_IS_EMU) {
264        /* restore fpu control register */
265        if (__copy_from_user(current->thread.fpcntl,
266                uc->uc_mcontext.fpregs.f_fpcntl, 12))
267            goto out;
268        /* restore all other fpu register */
269        if (__copy_from_user(current->thread.fp,
270                uc->uc_mcontext.fpregs.f_fpregs, 96))
271            goto out;
272        return 0;
273    }
274
275    if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
276        goto out;
277    if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
278        if (!CPU_IS_060)
279            context_size = fpstate[1];
280        /* Verify the frame format. */
281        if (!CPU_IS_060 && (fpstate[0] != fpu_version))
282            goto out;
283        if (CPU_IS_020_OR_030) {
284            if (m68k_fputype & FPU_68881 &&
285                !(context_size == 0x18 || context_size == 0xb4))
286                goto out;
287            if (m68k_fputype & FPU_68882 &&
288                !(context_size == 0x38 || context_size == 0xd4))
289                goto out;
290        } else if (CPU_IS_040) {
291            if (!(context_size == 0x00 ||
292                  context_size == 0x28 ||
293                  context_size == 0x60))
294                goto out;
295        } else if (CPU_IS_060) {
296            if (!(fpstate[3] == 0x00 ||
297                  fpstate[3] == 0x60 ||
298                  fpstate[3] == 0xe0))
299                goto out;
300        } else if (CPU_IS_CFV4E) {
301            pr_debug("restore coldfire rt v4e fpu"
302                 " state at %s\n", __func__);
303        } else
304            goto out;
305        if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
306                     sizeof(fpregs)))
307            goto out;
308#ifdef CONFIG_CFV4E
309                __asm__ volatile ("fmovem %0,%/fp0-%/fp7\n\t"
310                                  QCHIP_RESTORE_DIRECTIVE
311                                  : /* no outputs */
312                                  : "m" (fpregs.f_fpregs[0][0])
313                                  : "memory");
314        __asm__ volatile ("fmovel %0,%/fpcr"
315                  : : "m" (fpregs.f_fpcntl[0])
316                  : "memory" );
317        __asm__ volatile ("fmovel %0,%/fpsr"
318                  : : "m" (fpregs.f_fpcntl[1])
319                  : "memory" );
320        __asm__ volatile ("fmovel %0,%/fpiar"
321                  : : "m" (fpregs.f_fpcntl[2])
322                  : "memory" );
323#endif
324    }
325    if (context_size &&
326        __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
327                 context_size))
328        goto out;
329#ifdef CONFIG_CFV4E
330        __asm__ volatile ("frestore %0\n\t"
331                          QCHIP_RESTORE_DIRECTIVE : : "m" (*fpstate));
332#endif
333    err = 0;
334
335out:
336    return err;
337}
338#endif
339
340static inline int
341restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc,
342    void __user *fp, int *pd0)
343{
344    int fsize, formatvec;
345    struct sigcontext context;
346    int err = 0;
347
348    /* get previous context */
349    if (copy_from_user(&context, usc, sizeof(context)))
350        goto badframe;
351
352    /* restore passed registers */
353    regs->d1 = context.sc_d1;
354    regs->a0 = context.sc_a0;
355    regs->a1 = context.sc_a1;
356    regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
357    regs->pc = context.sc_pc;
358    regs->orig_d0 = -1; /* disable syscall checks */
359    wrusp(context.sc_usp);
360    formatvec = context.sc_formatvec;
361    regs->format = formatvec >> 12;
362    regs->vector = formatvec & 0xfff;
363
364#ifdef CONFIG_FPU
365    err = restore_fpu_state(&context);
366#endif
367
368    fsize = frame_extra_sizes[regs->format];
369    if (fsize < 0) {
370        /*
371         * user process trying to return with weird frame format
372         */
373#ifdef DEBUG
374        printk(KERN_DEBUG "user process returning with weird \
375            frame format\n");
376#endif
377        goto badframe;
378    }
379
380    /* OK. Make room on the supervisor stack for the extra junk,
381     * if necessary.
382     */
383
384    {
385        struct switch_stack *sw = (struct switch_stack *)regs - 1;
386        regs->d0 = context.sc_d0;
387#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
388        __asm__ __volatile__
389            (" movel %0,%/sp\n\t"
390             " bra ret_from_signal\n"
391             "4:\n"
392             ".section __ex_table,\"a\"\n"
393             " .align 4\n"
394             " .long 2b,4b\n"
395             ".previous"
396             : /* no outputs, it doesn't ever return */
397             : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
398               "n" (frame_offset), "a" (fp)
399             : "a0");
400#undef frame_offset
401        /*
402         * If we ever get here an exception occurred while
403         * building the above stack-frame.
404         */
405        goto badframe;
406    }
407
408    *pd0 = context.sc_d0;
409    return err;
410
411badframe:
412    return 1;
413}
414
415static inline int
416rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
417            struct ucontext __user *uc, int *pd0)
418{
419    int fsize, temp;
420    greg_t __user *gregs = uc->uc_mcontext.gregs;
421    unsigned long usp;
422    int err;
423
424    err = __get_user(temp, &uc->uc_mcontext.version);
425    if (temp != MCONTEXT_VERSION)
426        goto badframe;
427    /* restore passed registers */
428    err |= __get_user(regs->d0, &gregs[0]);
429    err |= __get_user(regs->d1, &gregs[1]);
430    err |= __get_user(regs->d2, &gregs[2]);
431    err |= __get_user(regs->d3, &gregs[3]);
432    err |= __get_user(regs->d4, &gregs[4]);
433    err |= __get_user(regs->d5, &gregs[5]);
434    err |= __get_user(sw->d6, &gregs[6]);
435    err |= __get_user(sw->d7, &gregs[7]);
436    err |= __get_user(regs->a0, &gregs[8]);
437    err |= __get_user(regs->a1, &gregs[9]);
438    err |= __get_user(regs->a2, &gregs[10]);
439    err |= __get_user(sw->a3, &gregs[11]);
440    err |= __get_user(sw->a4, &gregs[12]);
441    err |= __get_user(sw->a5, &gregs[13]);
442    err |= __get_user(sw->a6, &gregs[14]);
443    err |= __get_user(usp, &gregs[15]);
444    wrusp(usp);
445    err |= __get_user(regs->pc, &gregs[16]);
446    err |= __get_user(temp, &gregs[17]);
447    regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
448    regs->orig_d0 = -1; /* disable syscall checks */
449    err |= __get_user(temp, &uc->uc_formatvec);
450    regs->format = temp >> 12;
451    regs->vector = temp & 0xfff;
452
453#ifdef CONFIG_FPU
454    err |= rt_restore_fpu_state(uc);
455#endif
456
457    if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
458        goto badframe;
459
460    fsize = frame_extra_sizes[regs->format];
461    if (fsize < 0) {
462        /*
463         * user process trying to return with weird frame format
464         */
465#ifdef DEBUG
466        printk(KERN_DEBUG "user process returning with weird \
467            frame format\n");
468#endif
469        goto badframe;
470    }
471
472    /* OK. Make room on the supervisor stack for the extra junk,
473     * if necessary.
474     */
475
476    {
477#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
478        __asm__ __volatile__
479            (" movel %0,%/sp\n\t"
480             " bra ret_from_signal\n"
481             "4:\n"
482             ".section __ex_table,\"a\"\n"
483             " .align 4\n"
484             " .long 2b,4b\n"
485             ".previous"
486             : /* no outputs, it doesn't ever return */
487             : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
488               "n" (frame_offset), "a" (&uc->uc_extra)
489             : "a0");
490#undef frame_offset
491        /*
492         * If we ever get here an exception occurred while
493         * building the above stack-frame.
494         */
495        goto badframe;
496    }
497
498    *pd0 = regs->d0;
499    return err;
500
501badframe:
502    return 1;
503}
504
505asmlinkage int do_sigreturn(unsigned long __unused)
506{
507    struct switch_stack *sw = (struct switch_stack *) &__unused;
508    struct pt_regs *regs = (struct pt_regs *) (sw + 1);
509    unsigned long usp = rdusp();
510    struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
511    sigset_t set;
512    int d0;
513
514    if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
515        goto badframe;
516    if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
517        (_NSIG_WORDS > 1 &&
518         __copy_from_user(&set.sig[1], &frame->extramask,
519                  sizeof(frame->extramask))))
520        goto badframe;
521
522    sigdelsetmask(&set, ~_BLOCKABLE);
523    spin_lock_irq(&current->sighand->siglock);
524    current->blocked = set;
525    recalc_sigpending();
526    spin_unlock_irq(&current->sighand->siglock);
527
528    if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
529        goto badframe;
530    return d0;
531
532badframe:
533    force_sig(SIGSEGV, current);
534    return 0;
535}
536
537asmlinkage int do_rt_sigreturn(unsigned long __unused)
538{
539    struct switch_stack *sw = (struct switch_stack *) &__unused;
540    struct pt_regs *regs = (struct pt_regs *) (sw + 1);
541    unsigned long usp = rdusp();
542    struct rt_sigframe __user *frame =
543        (struct rt_sigframe __user *)(usp - 4);
544    sigset_t set;
545    int d0;
546
547    if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
548        goto badframe;
549    if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
550        goto badframe;
551
552    sigdelsetmask(&set, ~_BLOCKABLE);
553    spin_lock_irq(&current->sighand->siglock);
554    current->blocked = set;
555    recalc_sigpending();
556    spin_unlock_irq(&current->sighand->siglock);
557
558    if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
559        goto badframe;
560    return d0;
561
562badframe:
563    force_sig(SIGSEGV, current);
564    return 0;
565}
566
567#ifdef CONFIG_FPU
568/*
569 * Set up a signal frame.
570 */
571
572static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
573{
574    if (FPU_IS_EMU) {
575        /* save registers */
576        memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
577        memcpy(sc->sc_fpregs, current->thread.fp, 24);
578        return;
579    }
580
581#ifdef CONFIG_CFV4E
582        __asm__ volatile ("fsave %0\n\t"
583                          QCHIP_RESTORE_DIRECTIVE
584                          : : "m" (*sc->sc_fpstate) : "memory");
585#endif
586
587        if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
588                fpu_version = sc->sc_fpstate[0];
589                if (CPU_IS_020_OR_030 &&
590                    regs->vector >= (VEC_FPBRUC * 4) &&
591                    regs->vector <= (VEC_FPNAN * 4)) {
592                        /* Clear pending exception in 68882 idle frame */
593                        if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
594                                sc->sc_fpstate[0x38] |= 1 << 3;
595                }
596#ifdef CONFIG_CFV4E
597                  __asm__ volatile ("fmovemd %/fp0-%/fp1,%0"
598                                  : : "m" (sc->sc_fpregs[0][0])
599                                  : "memory");
600                 __asm__ volatile ("fmovel %/fpcr,%0"
601                                  : : "m" (sc->sc_fpcntl[0])
602                                  : "memory");
603                 __asm__ volatile ("fmovel %/fpsr,%0"
604                                  : : "m" (sc->sc_fpcntl[1])
605                                  : "memory");
606                 __asm__ volatile ("fmovel %/fpiar,%0"
607                                  : : "m" (sc->sc_fpcntl[2])
608                                  : "memory");
609
610#endif
611        }
612}
613
614static inline int rt_save_fpu_state(struct ucontext __user *uc,
615    struct pt_regs *regs)
616{
617    unsigned char fpstate[FPCONTEXT_SIZE];
618    int context_size = CPU_IS_060 ? 8 : 0;
619    int err = 0;
620
621    if (FPU_IS_EMU) {
622        /* save fpu control register */
623        err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl,
624                current->thread.fpcntl, 12);
625        /* save all other fpu register */
626        err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
627                current->thread.fp, 96);
628        return err;
629    }
630
631#ifdef CONFIG_CFV4E
632        __asm__ volatile ("fsave %0\n\t"
633                          QCHIP_RESTORE_DIRECTIVE
634                          : : "m" (*fpstate) : "memory");
635#endif
636    err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
637    if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
638        fpregset_t fpregs;
639        if (!CPU_IS_060)
640            context_size = fpstate[1];
641        fpu_version = fpstate[0];
642#ifdef CONFIG_CFV4E
643                  __asm__ volatile ("fmovemd %/fp0-%/fp7,%0"
644                                  : : "m" (fpregs.f_fpregs[0][0])
645                                  : "memory");
646                 __asm__ volatile ("fmovel %/fpcr,%0"
647                                  : : "m" (fpregs.f_fpcntl[0])
648                                  : "memory");
649                 __asm__ volatile ("fmovel %/fpsr,%0"
650                                  : : "m" (fpregs.f_fpcntl[1])
651                                  : "memory");
652                 __asm__ volatile ("fmovel %/fpiar,%0"
653                                  : : "m" (fpregs.f_fpcntl[2])
654                                  : "memory");
655#endif
656        err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
657                    sizeof(fpregs));
658    }
659    if (context_size)
660        err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
661                    context_size);
662    return err;
663
664
665    return err;
666}
667#endif
668
669static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
670                 unsigned long mask)
671{
672    sc->sc_mask = mask;
673    sc->sc_usp = rdusp();
674    sc->sc_d0 = regs->d0;
675    sc->sc_d1 = regs->d1;
676    sc->sc_a0 = regs->a0;
677    sc->sc_a1 = regs->a1;
678    sc->sc_sr = regs->sr;
679    sc->sc_pc = regs->pc;
680    sc->sc_formatvec = regs->format << 12 | regs->vector;
681#ifdef CONFIG_FPU
682    save_fpu_state(sc, regs);
683#endif
684}
685
686static inline int rt_setup_ucontext(struct ucontext __user *uc,
687    struct pt_regs *regs)
688{
689    struct switch_stack *sw = (struct switch_stack *)regs - 1;
690    greg_t __user *gregs = uc->uc_mcontext.gregs;
691    int err = 0;
692
693    err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
694    err |= __put_user(regs->d0, &gregs[0]);
695    err |= __put_user(regs->d1, &gregs[1]);
696    err |= __put_user(regs->d2, &gregs[2]);
697    err |= __put_user(regs->d3, &gregs[3]);
698    err |= __put_user(regs->d4, &gregs[4]);
699    err |= __put_user(regs->d5, &gregs[5]);
700    err |= __put_user(sw->d6, &gregs[6]);
701    err |= __put_user(sw->d7, &gregs[7]);
702    err |= __put_user(regs->a0, &gregs[8]);
703    err |= __put_user(regs->a1, &gregs[9]);
704    err |= __put_user(regs->a2, &gregs[10]);
705    err |= __put_user(sw->a3, &gregs[11]);
706    err |= __put_user(sw->a4, &gregs[12]);
707    err |= __put_user(sw->a5, &gregs[13]);
708    err |= __put_user(sw->a6, &gregs[14]);
709    err |= __put_user(rdusp(), &gregs[15]);
710    err |= __put_user(regs->pc, &gregs[16]);
711    err |= __put_user(regs->sr, &gregs[17]);
712    err |= __put_user((regs->format << 12) | regs->vector,
713              &uc->uc_formatvec);
714#ifdef CONFIG_FPU
715    err |= rt_save_fpu_state(uc, regs);
716#endif
717    return err;
718}
719
720static inline void push_cache(unsigned long vaddr)
721{
722#ifdef CONFIG_M5445X
723    pgd_t *pdir;
724    pmd_t *pmdp;
725    pte_t *ptep;
726    unsigned long paddr;
727
728    pdir = pgd_offset(current->mm, vaddr);
729    pmdp = pmd_offset(pdir, vaddr);
730    ptep = pte_offset_map(pmdp, vaddr);
731    paddr = ((pte_val(*ptep) & PAGE_MASK) | (vaddr & ~PAGE_MASK));
732    cf_icache_flush_range(paddr, paddr + 8);
733#elif CONFIG_M547X_8X
734    flush_icache_range(vaddr, vaddr + 8);
735#endif
736}
737
738static inline void __user *
739get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
740{
741    unsigned long usp;
742
743    /* Default to using normal stack. */
744    usp = rdusp();
745
746    /* This is the X/Open sanctioned signal stack switching. */
747    if (ka->sa.sa_flags & SA_ONSTACK) {
748        if (!sas_ss_flags(usp))
749            usp = current->sas_ss_sp + current->sas_ss_size;
750    }
751    return (void __user *)((usp - frame_size) & -8UL);
752}
753
754static void setup_frame(int sig, struct k_sigaction *ka,
755             sigset_t *set, struct pt_regs *regs)
756{
757    struct sigframe __user *frame;
758    int fsize = frame_extra_sizes[regs->format];
759    struct sigcontext context;
760    int err = 0;
761
762    if (fsize < 0) {
763#ifdef DEBUG
764        printk(KERN_DEBUG "setup_frame: Unknown frame format %#x\n",
765            regs->format);
766#endif
767        goto give_sigsegv;
768    }
769
770    frame = get_sigframe(ka, regs, sizeof(*frame));
771
772    err |= __put_user((current_thread_info()->exec_domain
773            && current_thread_info()->exec_domain->signal_invmap
774            && sig < 32
775            ? current_thread_info()->exec_domain->signal_invmap[sig]
776            : sig),
777            &frame->sig);
778
779    err |= __put_user(regs->vector, &frame->code);
780    err |= __put_user(&frame->sc, &frame->psc);
781
782    if (_NSIG_WORDS > 1)
783        err |= copy_to_user(frame->extramask, &set->sig[1],
784                    sizeof(frame->extramask));
785
786    setup_sigcontext(&context, regs, set->sig[0]);
787    err |= copy_to_user(&frame->sc, &context, sizeof(context));
788
789    /* Set up to return from userspace. */
790    err |= __put_user(frame->retcode, &frame->pretcode);
791    /* moveq #,d0; trap #0 */
792    err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
793              (long __user *)(frame->retcode));
794
795    if (err)
796        goto give_sigsegv;
797
798    push_cache((unsigned long) &frame->retcode);
799
800    /* Set up registers for signal handler */
801    wrusp((unsigned long) frame);
802    regs->pc = (unsigned long) ka->sa.sa_handler;
803
804adjust_stack:
805    /* Prepare to skip over the extra stuff in the exception frame. */
806    if (regs->stkadj) {
807        struct pt_regs *tregs =
808            (struct pt_regs *)((ulong)regs + regs->stkadj);
809#ifdef DEBUG
810        printk(KERN_DEBUG "Performing stackadjust=%04x\n",
811            regs->stkadj);
812#endif
813        /* This must be copied with decreasing addresses to
814           handle overlaps. */
815        tregs->vector = 0;
816        tregs->format = 0;
817        tregs->pc = regs->pc;
818        tregs->sr = regs->sr;
819    }
820    return;
821
822give_sigsegv:
823    force_sigsegv(sig, current);
824    goto adjust_stack;
825}
826
827static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
828    sigset_t *set, struct pt_regs *regs)
829{
830    struct rt_sigframe __user *frame;
831    int fsize = frame_extra_sizes[regs->format];
832    int err = 0;
833
834    if (fsize < 0) {
835#ifdef DEBUG
836        printk(KERN_DEBUG "setup_frame: Unknown frame format %#x\n",
837            regs->format);
838#endif
839        goto give_sigsegv;
840    }
841
842    frame = get_sigframe(ka, regs, sizeof(*frame));
843
844    if (fsize) {
845        err |= copy_to_user(&frame->uc.uc_extra, regs + 1, fsize);
846        regs->stkadj = fsize;
847    }
848
849    err |= __put_user((current_thread_info()->exec_domain
850            && current_thread_info()->exec_domain->signal_invmap
851            && sig < 32
852            ? current_thread_info()->exec_domain->signal_invmap[sig]
853            : sig),
854            &frame->sig);
855    err |= __put_user(&frame->info, &frame->pinfo);
856    err |= __put_user(&frame->uc, &frame->puc);
857    err |= copy_siginfo_to_user(&frame->info, info);
858
859    /* Create the ucontext. */
860    err |= __put_user(0, &frame->uc.uc_flags);
861    err |= __put_user(NULL, &frame->uc.uc_link);
862    err |= __put_user((void __user *)current->sas_ss_sp,
863              &frame->uc.uc_stack.ss_sp);
864    err |= __put_user(sas_ss_flags(rdusp()),
865              &frame->uc.uc_stack.ss_flags);
866    err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
867    err |= rt_setup_ucontext(&frame->uc, regs);
868    err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
869
870    /* Set up to return from userspace. */
871    err |= __put_user(frame->retcode, &frame->pretcode);
872
873    /* movel #__NR_rt_sigreturn(0xAD),d0; trap #0 */
874    err |= __put_user(0x203c0000, (long *)(frame->retcode + 0));
875    err |= __put_user(0x00ad4e40, (long *)(frame->retcode + 4));
876
877    if (err)
878        goto give_sigsegv;
879
880    push_cache((unsigned long) &frame->retcode);
881
882    /* Set up registers for signal handler */
883    wrusp((unsigned long) frame);
884    regs->pc = (unsigned long) ka->sa.sa_handler;
885
886adjust_stack:
887    /* Prepare to skip over the extra stuff in the exception frame. */
888    if (regs->stkadj) {
889        struct pt_regs *tregs =
890            (struct pt_regs *)((ulong)regs + regs->stkadj);
891#ifdef DEBUG
892        printk(KERN_DEBUG "Performing stackadjust=%04x\n",
893            regs->stkadj);
894#endif
895        /* This must be copied with decreasing addresses to
896           handle overlaps. */
897        tregs->vector = 0;
898        tregs->format = 0;
899        tregs->pc = regs->pc;
900        tregs->sr = regs->sr;
901    }
902    return;
903
904give_sigsegv:
905    force_sigsegv(sig, current);
906    goto adjust_stack;
907}
908
909static inline void
910handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
911{
912    switch (regs->d0) {
913    case -ERESTARTNOHAND:
914        if (!has_handler)
915            goto do_restart;
916        regs->d0 = -EINTR;
917        break;
918
919    case -ERESTARTSYS:
920        if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
921            regs->d0 = -EINTR;
922            break;
923        }
924    /* fallthrough */
925    case -ERESTARTNOINTR:
926do_restart:
927        regs->d0 = regs->orig_d0;
928        regs->pc -= 2;
929        break;
930    }
931}
932
933/*
934 * OK, we're invoking a handler
935 */
936static void
937handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
938          sigset_t *oldset, struct pt_regs *regs)
939{
940    /* are we from a system call? */
941    if (regs->orig_d0 >= 0)
942        /* If so, check system call restarting.. */
943        handle_restart(regs, ka, 1);
944
945    /* set up the stack frame */
946    if (ka->sa.sa_flags & SA_SIGINFO)
947        setup_rt_frame(sig, ka, info, oldset, regs);
948    else
949        setup_frame(sig, ka, oldset, regs);
950
951    if (ka->sa.sa_flags & SA_ONESHOT)
952        ka->sa.sa_handler = SIG_DFL;
953
954    spin_lock_irq(&current->sighand->siglock);
955    sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
956    if (!(ka->sa.sa_flags & SA_NODEFER))
957        sigaddset(&current->blocked, sig);
958    recalc_sigpending();
959    spin_unlock_irq(&current->sighand->siglock);
960}
961
962/*
963 * Note that 'init' is a special process: it doesn't get signals it doesn't
964 * want to handle. Thus you cannot kill init even with a SIGKILL even by
965 * mistake.
966 */
967asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
968{
969    siginfo_t info;
970    struct k_sigaction ka;
971    int signr;
972
973    current->thread.esp0 = (unsigned long) regs;
974
975    if (!oldset)
976        oldset = &current->blocked;
977
978    signr = get_signal_to_deliver(&info, &ka, regs, NULL);
979    if (signr > 0) {
980        /* Whee! Actually deliver the signal. */
981        handle_signal(signr, &ka, &info, oldset, regs);
982        return 1;
983    }
984
985    /* Did we come from a system call? */
986    if (regs->orig_d0 >= 0)
987        /* Restart the system call - no handlers present */
988        handle_restart(regs, NULL, 0);
989
990    return 0;
991}
992

Archive Download this file



interactive