10c22fafdSGreg Ungerer /*
20c22fafdSGreg Ungerer * linux/arch/m68k/kernel/signal.c
30c22fafdSGreg Ungerer *
40c22fafdSGreg Ungerer * Copyright (C) 1991, 1992 Linus Torvalds
50c22fafdSGreg Ungerer *
60c22fafdSGreg Ungerer * This file is subject to the terms and conditions of the GNU General Public
70c22fafdSGreg Ungerer * License. See the file COPYING in the main directory of this archive
80c22fafdSGreg Ungerer * for more details.
90c22fafdSGreg Ungerer */
100c22fafdSGreg Ungerer
110c22fafdSGreg Ungerer /*
120c22fafdSGreg Ungerer * Linux/m68k support by Hamish Macdonald
130c22fafdSGreg Ungerer *
140c22fafdSGreg Ungerer * 68060 fixes by Jesper Skov
150c22fafdSGreg Ungerer *
160c22fafdSGreg Ungerer * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab
170c22fafdSGreg Ungerer *
180c22fafdSGreg Ungerer * mathemu support by Roman Zippel
190c22fafdSGreg Ungerer * (Note: fpstate in the signal context is completely ignored for the emulator
200c22fafdSGreg Ungerer * and the internal floating point format is put on stack)
210c22fafdSGreg Ungerer */
220c22fafdSGreg Ungerer
230c22fafdSGreg Ungerer /*
240c22fafdSGreg Ungerer * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
250c22fafdSGreg Ungerer * Atari :-) Current limitation: Only one sigstack can be active at one time.
260c22fafdSGreg Ungerer * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
270c22fafdSGreg Ungerer * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
280c22fafdSGreg Ungerer * signal handlers!
290c22fafdSGreg Ungerer */
300c22fafdSGreg Ungerer
310c22fafdSGreg Ungerer #include <linux/sched.h>
320c22fafdSGreg Ungerer #include <linux/mm.h>
330c22fafdSGreg Ungerer #include <linux/kernel.h>
340c22fafdSGreg Ungerer #include <linux/signal.h>
350c22fafdSGreg Ungerer #include <linux/syscalls.h>
360c22fafdSGreg Ungerer #include <linux/errno.h>
370c22fafdSGreg Ungerer #include <linux/wait.h>
380c22fafdSGreg Ungerer #include <linux/ptrace.h>
390c22fafdSGreg Ungerer #include <linux/unistd.h>
400c22fafdSGreg Ungerer #include <linux/stddef.h>
410c22fafdSGreg Ungerer #include <linux/highuid.h>
420c22fafdSGreg Ungerer #include <linux/personality.h>
430c22fafdSGreg Ungerer #include <linux/tty.h>
440c22fafdSGreg Ungerer #include <linux/binfmts.h>
456736e65eSPaul Gortmaker #include <linux/extable.h>
4603248addSEric W. Biederman #include <linux/resume_user_mode.h>
470c22fafdSGreg Ungerer
480c22fafdSGreg Ungerer #include <asm/setup.h>
497c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
500c22fafdSGreg Ungerer #include <asm/traps.h>
510c22fafdSGreg Ungerer #include <asm/ucontext.h>
5242cb38bcSAlexander Stein #include <asm/cacheflush.h>
530c22fafdSGreg Ungerer
5466d857b0SGreg Ungerer #ifdef CONFIG_MMU
550c22fafdSGreg Ungerer
560c22fafdSGreg Ungerer /*
570c22fafdSGreg Ungerer * Handle the slight differences in classic 68k and ColdFire trap frames.
580c22fafdSGreg Ungerer */
590c22fafdSGreg Ungerer #ifdef CONFIG_COLDFIRE
600c22fafdSGreg Ungerer #define FORMAT 4
610c22fafdSGreg Ungerer #define FMT4SIZE 0
6200ebfe58SMaxim Kuvyrkov #else
630c22fafdSGreg Ungerer #define FORMAT 0
645f5f2949SGustavo A. R. Silva #define FMT4SIZE sizeof_field(struct frame, un.fmt4)
6500ebfe58SMaxim Kuvyrkov #endif
660c22fafdSGreg Ungerer
670c22fafdSGreg Ungerer static const int frame_size_change[16] = {
685f5f2949SGustavo A. R. Silva [1] = -1, /* sizeof_field(struct frame, un.fmt1), */
695f5f2949SGustavo A. R. Silva [2] = sizeof_field(struct frame, un.fmt2),
705f5f2949SGustavo A. R. Silva [3] = sizeof_field(struct frame, un.fmt3),
710c22fafdSGreg Ungerer [4] = FMT4SIZE,
725f5f2949SGustavo A. R. Silva [5] = -1, /* sizeof_field(struct frame, un.fmt5), */
735f5f2949SGustavo A. R. Silva [6] = -1, /* sizeof_field(struct frame, un.fmt6), */
745f5f2949SGustavo A. R. Silva [7] = sizeof_field(struct frame, un.fmt7),
755f5f2949SGustavo A. R. Silva [8] = -1, /* sizeof_field(struct frame, un.fmt8), */
765f5f2949SGustavo A. R. Silva [9] = sizeof_field(struct frame, un.fmt9),
775f5f2949SGustavo A. R. Silva [10] = sizeof_field(struct frame, un.fmta),
785f5f2949SGustavo A. R. Silva [11] = sizeof_field(struct frame, un.fmtb),
795f5f2949SGustavo A. R. Silva [12] = -1, /* sizeof_field(struct frame, un.fmtc), */
805f5f2949SGustavo A. R. Silva [13] = -1, /* sizeof_field(struct frame, un.fmtd), */
815f5f2949SGustavo A. R. Silva [14] = -1, /* sizeof_field(struct frame, un.fmte), */
825f5f2949SGustavo A. R. Silva [15] = -1, /* sizeof_field(struct frame, un.fmtf), */
830c22fafdSGreg Ungerer };
840c22fafdSGreg Ungerer
frame_extra_sizes(int f)850c22fafdSGreg Ungerer static inline int frame_extra_sizes(int f)
860c22fafdSGreg Ungerer {
870c22fafdSGreg Ungerer return frame_size_change[f];
880c22fafdSGreg Ungerer }
890c22fafdSGreg Ungerer
fixup_exception(struct pt_regs * regs)9068acfdcbSAl Viro int fixup_exception(struct pt_regs *regs)
910c22fafdSGreg Ungerer {
920c22fafdSGreg Ungerer const struct exception_table_entry *fixup;
930c22fafdSGreg Ungerer struct pt_regs *tregs;
940c22fafdSGreg Ungerer
950c22fafdSGreg Ungerer /* Are we prepared to handle this kernel fault? */
960c22fafdSGreg Ungerer fixup = search_exception_tables(regs->pc);
970c22fafdSGreg Ungerer if (!fixup)
980c22fafdSGreg Ungerer return 0;
990c22fafdSGreg Ungerer
1000c22fafdSGreg Ungerer /* Create a new four word stack frame, discarding the old one. */
1010c22fafdSGreg Ungerer regs->stkadj = frame_extra_sizes(regs->format);
1020c22fafdSGreg Ungerer tregs = (struct pt_regs *)((long)regs + regs->stkadj);
1030c22fafdSGreg Ungerer tregs->vector = regs->vector;
1040c22fafdSGreg Ungerer tregs->format = FORMAT;
1050c22fafdSGreg Ungerer tregs->pc = fixup->fixup;
1060c22fafdSGreg Ungerer tregs->sr = regs->sr;
1070c22fafdSGreg Ungerer
1080c22fafdSGreg Ungerer return 1;
1090c22fafdSGreg Ungerer }
1100c22fafdSGreg Ungerer
push_cache(unsigned long vaddr)1110c22fafdSGreg Ungerer static inline void push_cache (unsigned long vaddr)
1120c22fafdSGreg Ungerer {
1130c22fafdSGreg Ungerer /*
1140c22fafdSGreg Ungerer * Using the old cache_push_v() was really a big waste.
1150c22fafdSGreg Ungerer *
1160c22fafdSGreg Ungerer * What we are trying to do is to flush 8 bytes to ram.
1170c22fafdSGreg Ungerer * Flushing 2 cache lines of 16 bytes is much cheaper than
1180c22fafdSGreg Ungerer * flushing 1 or 2 pages, as previously done in
1190c22fafdSGreg Ungerer * cache_push_v().
1200c22fafdSGreg Ungerer * Jes
1210c22fafdSGreg Ungerer */
1220c22fafdSGreg Ungerer if (CPU_IS_040) {
1230c22fafdSGreg Ungerer unsigned long temp;
1240c22fafdSGreg Ungerer
1250c22fafdSGreg Ungerer __asm__ __volatile__ (".chip 68040\n\t"
1260c22fafdSGreg Ungerer "nop\n\t"
1270c22fafdSGreg Ungerer "ptestr (%1)\n\t"
1280c22fafdSGreg Ungerer "movec %%mmusr,%0\n\t"
1290c22fafdSGreg Ungerer ".chip 68k"
1300c22fafdSGreg Ungerer : "=r" (temp)
1310c22fafdSGreg Ungerer : "a" (vaddr));
1320c22fafdSGreg Ungerer
1330c22fafdSGreg Ungerer temp &= PAGE_MASK;
1340c22fafdSGreg Ungerer temp |= vaddr & ~PAGE_MASK;
1350c22fafdSGreg Ungerer
1360c22fafdSGreg Ungerer __asm__ __volatile__ (".chip 68040\n\t"
1370c22fafdSGreg Ungerer "nop\n\t"
1380c22fafdSGreg Ungerer "cpushl %%bc,(%0)\n\t"
1390c22fafdSGreg Ungerer ".chip 68k"
1400c22fafdSGreg Ungerer : : "a" (temp));
1410c22fafdSGreg Ungerer }
1420c22fafdSGreg Ungerer else if (CPU_IS_060) {
1430c22fafdSGreg Ungerer unsigned long temp;
1440c22fafdSGreg Ungerer __asm__ __volatile__ (".chip 68060\n\t"
1450c22fafdSGreg Ungerer "plpar (%0)\n\t"
1460c22fafdSGreg Ungerer ".chip 68k"
1470c22fafdSGreg Ungerer : "=a" (temp)
1480c22fafdSGreg Ungerer : "0" (vaddr));
1490c22fafdSGreg Ungerer __asm__ __volatile__ (".chip 68060\n\t"
1500c22fafdSGreg Ungerer "cpushl %%bc,(%0)\n\t"
1510c22fafdSGreg Ungerer ".chip 68k"
1520c22fafdSGreg Ungerer : : "a" (temp));
1530c22fafdSGreg Ungerer } else if (!CPU_IS_COLDFIRE) {
1540c22fafdSGreg Ungerer /*
1550c22fafdSGreg Ungerer * 68030/68020 have no writeback cache;
1560c22fafdSGreg Ungerer * still need to clear icache.
1570c22fafdSGreg Ungerer * Note that vaddr is guaranteed to be long word aligned.
1580c22fafdSGreg Ungerer */
1590c22fafdSGreg Ungerer unsigned long temp;
1600c22fafdSGreg Ungerer asm volatile ("movec %%cacr,%0" : "=r" (temp));
1610c22fafdSGreg Ungerer temp += 4;
1620c22fafdSGreg Ungerer asm volatile ("movec %0,%%caar\n\t"
1630c22fafdSGreg Ungerer "movec %1,%%cacr"
1640c22fafdSGreg Ungerer : : "r" (vaddr), "r" (temp));
1650c22fafdSGreg Ungerer asm volatile ("movec %0,%%caar\n\t"
1660c22fafdSGreg Ungerer "movec %1,%%cacr"
1670c22fafdSGreg Ungerer : : "r" (vaddr + 4), "r" (temp));
16842cb38bcSAlexander Stein } else {
16942cb38bcSAlexander Stein /* CPU_IS_COLDFIRE */
17042cb38bcSAlexander Stein #if defined(CONFIG_CACHE_COPYBACK)
17142cb38bcSAlexander Stein flush_cf_dcache(0, DCACHE_MAX_ADDR);
17242cb38bcSAlexander Stein #endif
17342cb38bcSAlexander Stein /* Invalidate instruction cache for the pushed bytes */
17442cb38bcSAlexander Stein clear_cf_icache(vaddr, vaddr + 8);
1750c22fafdSGreg Ungerer }
1760c22fafdSGreg Ungerer }
1770c22fafdSGreg Ungerer
adjustformat(struct pt_regs * regs)1780c22fafdSGreg Ungerer static inline void adjustformat(struct pt_regs *regs)
1790c22fafdSGreg Ungerer {
1800c22fafdSGreg Ungerer }
1810c22fafdSGreg Ungerer
save_a5_state(struct sigcontext * sc,struct pt_regs * regs)1820c22fafdSGreg Ungerer static inline void save_a5_state(struct sigcontext *sc, struct pt_regs *regs)
1830c22fafdSGreg Ungerer {
1840c22fafdSGreg Ungerer }
1850c22fafdSGreg Ungerer
1860c22fafdSGreg Ungerer #else /* CONFIG_MMU */
1870c22fafdSGreg Ungerer
1880c22fafdSGreg Ungerer void ret_from_user_signal(void);
1890c22fafdSGreg Ungerer void ret_from_user_rt_signal(void);
1900c22fafdSGreg Ungerer
frame_extra_sizes(int f)1910c22fafdSGreg Ungerer static inline int frame_extra_sizes(int f)
1920c22fafdSGreg Ungerer {
1930c22fafdSGreg Ungerer /* No frame size adjustments required on non-MMU CPUs */
1940c22fafdSGreg Ungerer return 0;
1950c22fafdSGreg Ungerer }
1960c22fafdSGreg Ungerer
adjustformat(struct pt_regs * regs)1970c22fafdSGreg Ungerer static inline void adjustformat(struct pt_regs *regs)
1980c22fafdSGreg Ungerer {
1990c22fafdSGreg Ungerer /*
2000c22fafdSGreg Ungerer * set format byte to make stack appear modulo 4, which it will
2010c22fafdSGreg Ungerer * be when doing the rte
2020c22fafdSGreg Ungerer */
2030c22fafdSGreg Ungerer regs->format = 0x4;
2040c22fafdSGreg Ungerer }
2050c22fafdSGreg Ungerer
save_a5_state(struct sigcontext * sc,struct pt_regs * regs)2060c22fafdSGreg Ungerer static inline void save_a5_state(struct sigcontext *sc, struct pt_regs *regs)
2070c22fafdSGreg Ungerer {
2080c22fafdSGreg Ungerer sc->sc_a5 = ((struct switch_stack *)regs - 1)->a5;
2090c22fafdSGreg Ungerer }
2100c22fafdSGreg Ungerer
push_cache(unsigned long vaddr)2110c22fafdSGreg Ungerer static inline void push_cache(unsigned long vaddr)
2120c22fafdSGreg Ungerer {
2130c22fafdSGreg Ungerer }
2140c22fafdSGreg Ungerer
2150c22fafdSGreg Ungerer #endif /* CONFIG_MMU */
2160c22fafdSGreg Ungerer
2170c22fafdSGreg Ungerer /*
2180c22fafdSGreg Ungerer * Do a signal return; undo the signal stack.
2190c22fafdSGreg Ungerer *
2200c22fafdSGreg Ungerer * Keep the return code on the stack quadword aligned!
2210c22fafdSGreg Ungerer * That makes the cache flush below easier.
2220c22fafdSGreg Ungerer */
2230c22fafdSGreg Ungerer
2240c22fafdSGreg Ungerer struct sigframe
2250c22fafdSGreg Ungerer {
2260c22fafdSGreg Ungerer char __user *pretcode;
2270c22fafdSGreg Ungerer int sig;
2280c22fafdSGreg Ungerer int code;
2290c22fafdSGreg Ungerer struct sigcontext __user *psc;
2300c22fafdSGreg Ungerer char retcode[8];
2310c22fafdSGreg Ungerer unsigned long extramask[_NSIG_WORDS-1];
2320c22fafdSGreg Ungerer struct sigcontext sc;
2330c22fafdSGreg Ungerer };
2340c22fafdSGreg Ungerer
2350c22fafdSGreg Ungerer struct rt_sigframe
2360c22fafdSGreg Ungerer {
2370c22fafdSGreg Ungerer char __user *pretcode;
2380c22fafdSGreg Ungerer int sig;
2390c22fafdSGreg Ungerer struct siginfo __user *pinfo;
2400c22fafdSGreg Ungerer void __user *puc;
2410c22fafdSGreg Ungerer char retcode[8];
2420c22fafdSGreg Ungerer struct siginfo info;
2430c22fafdSGreg Ungerer struct ucontext uc;
2440c22fafdSGreg Ungerer };
2450c22fafdSGreg Ungerer
2460c22fafdSGreg Ungerer #define FPCONTEXT_SIZE 216
2470c22fafdSGreg Ungerer #define uc_fpstate uc_filler[0]
2480c22fafdSGreg Ungerer #define uc_formatvec uc_filler[FPCONTEXT_SIZE/4]
2490c22fafdSGreg Ungerer #define uc_extra uc_filler[FPCONTEXT_SIZE/4+1]
2500c22fafdSGreg Ungerer
2510c22fafdSGreg Ungerer #ifdef CONFIG_FPU
2520c22fafdSGreg Ungerer
2530c22fafdSGreg Ungerer static unsigned char fpu_version; /* version number of fpu, set by setup_frame */
2540c22fafdSGreg Ungerer
restore_fpu_state(struct sigcontext * sc)2550c22fafdSGreg Ungerer static inline int restore_fpu_state(struct sigcontext *sc)
2560c22fafdSGreg Ungerer {
2570c22fafdSGreg Ungerer int err = 1;
2580c22fafdSGreg Ungerer
2590c22fafdSGreg Ungerer if (FPU_IS_EMU) {
2600c22fafdSGreg Ungerer /* restore registers */
2610c22fafdSGreg Ungerer memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
2620c22fafdSGreg Ungerer memcpy(current->thread.fp, sc->sc_fpregs, 24);
2630c22fafdSGreg Ungerer return 0;
2640c22fafdSGreg Ungerer }
2650c22fafdSGreg Ungerer
2660c22fafdSGreg Ungerer if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
2670c22fafdSGreg Ungerer /* Verify the frame format. */
2680c22fafdSGreg Ungerer if (!(CPU_IS_060 || CPU_IS_COLDFIRE) &&
2690c22fafdSGreg Ungerer (sc->sc_fpstate[0] != fpu_version))
2700c22fafdSGreg Ungerer goto out;
2710c22fafdSGreg Ungerer if (CPU_IS_020_OR_030) {
2720c22fafdSGreg Ungerer if (m68k_fputype & FPU_68881 &&
2730c22fafdSGreg Ungerer !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
2740c22fafdSGreg Ungerer goto out;
2750c22fafdSGreg Ungerer if (m68k_fputype & FPU_68882 &&
2760c22fafdSGreg Ungerer !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
2770c22fafdSGreg Ungerer goto out;
2780c22fafdSGreg Ungerer } else if (CPU_IS_040) {
2790c22fafdSGreg Ungerer if (!(sc->sc_fpstate[1] == 0x00 ||
2800c22fafdSGreg Ungerer sc->sc_fpstate[1] == 0x28 ||
2810c22fafdSGreg Ungerer sc->sc_fpstate[1] == 0x60))
2820c22fafdSGreg Ungerer goto out;
2830c22fafdSGreg Ungerer } else if (CPU_IS_060) {
2840c22fafdSGreg Ungerer if (!(sc->sc_fpstate[3] == 0x00 ||
2850c22fafdSGreg Ungerer sc->sc_fpstate[3] == 0x60 ||
2860c22fafdSGreg Ungerer sc->sc_fpstate[3] == 0xe0))
2870c22fafdSGreg Ungerer goto out;
2880c22fafdSGreg Ungerer } else if (CPU_IS_COLDFIRE) {
2890c22fafdSGreg Ungerer if (!(sc->sc_fpstate[0] == 0x00 ||
2900c22fafdSGreg Ungerer sc->sc_fpstate[0] == 0x05 ||
2910c22fafdSGreg Ungerer sc->sc_fpstate[0] == 0xe5))
2920c22fafdSGreg Ungerer goto out;
2930c22fafdSGreg Ungerer } else
2940c22fafdSGreg Ungerer goto out;
2950c22fafdSGreg Ungerer
2960c22fafdSGreg Ungerer if (CPU_IS_COLDFIRE) {
2970c22fafdSGreg Ungerer __asm__ volatile ("fmovemd %0,%%fp0-%%fp1\n\t"
2980c22fafdSGreg Ungerer "fmovel %1,%%fpcr\n\t"
2990c22fafdSGreg Ungerer "fmovel %2,%%fpsr\n\t"
3000c22fafdSGreg Ungerer "fmovel %3,%%fpiar"
3010c22fafdSGreg Ungerer : /* no outputs */
3020c22fafdSGreg Ungerer : "m" (sc->sc_fpregs[0]),
3030c22fafdSGreg Ungerer "m" (sc->sc_fpcntl[0]),
3040c22fafdSGreg Ungerer "m" (sc->sc_fpcntl[1]),
3050c22fafdSGreg Ungerer "m" (sc->sc_fpcntl[2]));
3060c22fafdSGreg Ungerer } else {
3070c22fafdSGreg Ungerer __asm__ volatile (".chip 68k/68881\n\t"
3080c22fafdSGreg Ungerer "fmovemx %0,%%fp0-%%fp1\n\t"
3090c22fafdSGreg Ungerer "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
3100c22fafdSGreg Ungerer ".chip 68k"
3110c22fafdSGreg Ungerer : /* no outputs */
3120c22fafdSGreg Ungerer : "m" (*sc->sc_fpregs),
3130c22fafdSGreg Ungerer "m" (*sc->sc_fpcntl));
3140c22fafdSGreg Ungerer }
3150c22fafdSGreg Ungerer }
3160c22fafdSGreg Ungerer
3170c22fafdSGreg Ungerer if (CPU_IS_COLDFIRE) {
3180c22fafdSGreg Ungerer __asm__ volatile ("frestore %0" : : "m" (*sc->sc_fpstate));
3190c22fafdSGreg Ungerer } else {
3200c22fafdSGreg Ungerer __asm__ volatile (".chip 68k/68881\n\t"
3210c22fafdSGreg Ungerer "frestore %0\n\t"
3220c22fafdSGreg Ungerer ".chip 68k"
3230c22fafdSGreg Ungerer : : "m" (*sc->sc_fpstate));
3240c22fafdSGreg Ungerer }
3250c22fafdSGreg Ungerer err = 0;
3260c22fafdSGreg Ungerer
3270c22fafdSGreg Ungerer out:
3280c22fafdSGreg Ungerer return err;
3290c22fafdSGreg Ungerer }
3300c22fafdSGreg Ungerer
rt_restore_fpu_state(struct ucontext __user * uc)3310c22fafdSGreg Ungerer static inline int rt_restore_fpu_state(struct ucontext __user *uc)
3320c22fafdSGreg Ungerer {
3330c22fafdSGreg Ungerer unsigned char fpstate[FPCONTEXT_SIZE];
3340c22fafdSGreg Ungerer int context_size = CPU_IS_060 ? 8 : (CPU_IS_COLDFIRE ? 12 : 0);
3350c22fafdSGreg Ungerer fpregset_t fpregs;
3360c22fafdSGreg Ungerer int err = 1;
3370c22fafdSGreg Ungerer
3380c22fafdSGreg Ungerer if (FPU_IS_EMU) {
3390c22fafdSGreg Ungerer /* restore fpu control register */
3400c22fafdSGreg Ungerer if (__copy_from_user(current->thread.fpcntl,
3410c22fafdSGreg Ungerer uc->uc_mcontext.fpregs.f_fpcntl, 12))
3420c22fafdSGreg Ungerer goto out;
3430c22fafdSGreg Ungerer /* restore all other fpu register */
3440c22fafdSGreg Ungerer if (__copy_from_user(current->thread.fp,
3450c22fafdSGreg Ungerer uc->uc_mcontext.fpregs.f_fpregs, 96))
3460c22fafdSGreg Ungerer goto out;
3470c22fafdSGreg Ungerer return 0;
3480c22fafdSGreg Ungerer }
3490c22fafdSGreg Ungerer
3500c22fafdSGreg Ungerer if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
3510c22fafdSGreg Ungerer goto out;
3520c22fafdSGreg Ungerer if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
3530c22fafdSGreg Ungerer if (!(CPU_IS_060 || CPU_IS_COLDFIRE))
3540c22fafdSGreg Ungerer context_size = fpstate[1];
3550c22fafdSGreg Ungerer /* Verify the frame format. */
3560c22fafdSGreg Ungerer if (!(CPU_IS_060 || CPU_IS_COLDFIRE) &&
3570c22fafdSGreg Ungerer (fpstate[0] != fpu_version))
3580c22fafdSGreg Ungerer goto out;
3590c22fafdSGreg Ungerer if (CPU_IS_020_OR_030) {
3600c22fafdSGreg Ungerer if (m68k_fputype & FPU_68881 &&
3610c22fafdSGreg Ungerer !(context_size == 0x18 || context_size == 0xb4))
3620c22fafdSGreg Ungerer goto out;
3630c22fafdSGreg Ungerer if (m68k_fputype & FPU_68882 &&
3640c22fafdSGreg Ungerer !(context_size == 0x38 || context_size == 0xd4))
3650c22fafdSGreg Ungerer goto out;
3660c22fafdSGreg Ungerer } else if (CPU_IS_040) {
3670c22fafdSGreg Ungerer if (!(context_size == 0x00 ||
3680c22fafdSGreg Ungerer context_size == 0x28 ||
3690c22fafdSGreg Ungerer context_size == 0x60))
3700c22fafdSGreg Ungerer goto out;
3710c22fafdSGreg Ungerer } else if (CPU_IS_060) {
3720c22fafdSGreg Ungerer if (!(fpstate[3] == 0x00 ||
3730c22fafdSGreg Ungerer fpstate[3] == 0x60 ||
3740c22fafdSGreg Ungerer fpstate[3] == 0xe0))
3750c22fafdSGreg Ungerer goto out;
3760c22fafdSGreg Ungerer } else if (CPU_IS_COLDFIRE) {
3770c22fafdSGreg Ungerer if (!(fpstate[3] == 0x00 ||
3780c22fafdSGreg Ungerer fpstate[3] == 0x05 ||
3790c22fafdSGreg Ungerer fpstate[3] == 0xe5))
3800c22fafdSGreg Ungerer goto out;
3810c22fafdSGreg Ungerer } else
3820c22fafdSGreg Ungerer goto out;
3830c22fafdSGreg Ungerer if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
3840c22fafdSGreg Ungerer sizeof(fpregs)))
3850c22fafdSGreg Ungerer goto out;
3860c22fafdSGreg Ungerer
3870c22fafdSGreg Ungerer if (CPU_IS_COLDFIRE) {
3880c22fafdSGreg Ungerer __asm__ volatile ("fmovemd %0,%%fp0-%%fp7\n\t"
3890c22fafdSGreg Ungerer "fmovel %1,%%fpcr\n\t"
3900c22fafdSGreg Ungerer "fmovel %2,%%fpsr\n\t"
3910c22fafdSGreg Ungerer "fmovel %3,%%fpiar"
3920c22fafdSGreg Ungerer : /* no outputs */
3930c22fafdSGreg Ungerer : "m" (fpregs.f_fpregs[0]),
3940c22fafdSGreg Ungerer "m" (fpregs.f_fpcntl[0]),
3950c22fafdSGreg Ungerer "m" (fpregs.f_fpcntl[1]),
3960c22fafdSGreg Ungerer "m" (fpregs.f_fpcntl[2]));
3970c22fafdSGreg Ungerer } else {
3980c22fafdSGreg Ungerer __asm__ volatile (".chip 68k/68881\n\t"
3990c22fafdSGreg Ungerer "fmovemx %0,%%fp0-%%fp7\n\t"
4000c22fafdSGreg Ungerer "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
4010c22fafdSGreg Ungerer ".chip 68k"
4020c22fafdSGreg Ungerer : /* no outputs */
4030c22fafdSGreg Ungerer : "m" (*fpregs.f_fpregs),
4040c22fafdSGreg Ungerer "m" (*fpregs.f_fpcntl));
4050c22fafdSGreg Ungerer }
4060c22fafdSGreg Ungerer }
4070c22fafdSGreg Ungerer if (context_size &&
4080c22fafdSGreg Ungerer __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
4090c22fafdSGreg Ungerer context_size))
4100c22fafdSGreg Ungerer goto out;
4110c22fafdSGreg Ungerer
4120c22fafdSGreg Ungerer if (CPU_IS_COLDFIRE) {
4130c22fafdSGreg Ungerer __asm__ volatile ("frestore %0" : : "m" (*fpstate));
4140c22fafdSGreg Ungerer } else {
4150c22fafdSGreg Ungerer __asm__ volatile (".chip 68k/68881\n\t"
4160c22fafdSGreg Ungerer "frestore %0\n\t"
4170c22fafdSGreg Ungerer ".chip 68k"
4180c22fafdSGreg Ungerer : : "m" (*fpstate));
4190c22fafdSGreg Ungerer }
4200c22fafdSGreg Ungerer err = 0;
4210c22fafdSGreg Ungerer
4220c22fafdSGreg Ungerer out:
4230c22fafdSGreg Ungerer return err;
4240c22fafdSGreg Ungerer }
4250c22fafdSGreg Ungerer
4260c22fafdSGreg Ungerer /*
4270c22fafdSGreg Ungerer * Set up a signal frame.
4280c22fafdSGreg Ungerer */
save_fpu_state(struct sigcontext * sc,struct pt_regs * regs)4290c22fafdSGreg Ungerer static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
4300c22fafdSGreg Ungerer {
4310c22fafdSGreg Ungerer if (FPU_IS_EMU) {
4320c22fafdSGreg Ungerer /* save registers */
4330c22fafdSGreg Ungerer memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
4340c22fafdSGreg Ungerer memcpy(sc->sc_fpregs, current->thread.fp, 24);
4350c22fafdSGreg Ungerer return;
4360c22fafdSGreg Ungerer }
4370c22fafdSGreg Ungerer
4380c22fafdSGreg Ungerer if (CPU_IS_COLDFIRE) {
4390c22fafdSGreg Ungerer __asm__ volatile ("fsave %0"
4400c22fafdSGreg Ungerer : : "m" (*sc->sc_fpstate) : "memory");
4410c22fafdSGreg Ungerer } else {
4420c22fafdSGreg Ungerer __asm__ volatile (".chip 68k/68881\n\t"
4430c22fafdSGreg Ungerer "fsave %0\n\t"
4440c22fafdSGreg Ungerer ".chip 68k"
4450c22fafdSGreg Ungerer : : "m" (*sc->sc_fpstate) : "memory");
4460c22fafdSGreg Ungerer }
4470c22fafdSGreg Ungerer
4480c22fafdSGreg Ungerer if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
4490c22fafdSGreg Ungerer fpu_version = sc->sc_fpstate[0];
4504bb0bd81SAl Viro if (CPU_IS_020_OR_030 && !regs->stkadj &&
4510c22fafdSGreg Ungerer regs->vector >= (VEC_FPBRUC * 4) &&
4520c22fafdSGreg Ungerer regs->vector <= (VEC_FPNAN * 4)) {
4530c22fafdSGreg Ungerer /* Clear pending exception in 68882 idle frame */
4540c22fafdSGreg Ungerer if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
4550c22fafdSGreg Ungerer sc->sc_fpstate[0x38] |= 1 << 3;
4560c22fafdSGreg Ungerer }
4570c22fafdSGreg Ungerer
4580c22fafdSGreg Ungerer if (CPU_IS_COLDFIRE) {
4590c22fafdSGreg Ungerer __asm__ volatile ("fmovemd %%fp0-%%fp1,%0\n\t"
4600c22fafdSGreg Ungerer "fmovel %%fpcr,%1\n\t"
4610c22fafdSGreg Ungerer "fmovel %%fpsr,%2\n\t"
4620c22fafdSGreg Ungerer "fmovel %%fpiar,%3"
4630c22fafdSGreg Ungerer : "=m" (sc->sc_fpregs[0]),
4640c22fafdSGreg Ungerer "=m" (sc->sc_fpcntl[0]),
4650c22fafdSGreg Ungerer "=m" (sc->sc_fpcntl[1]),
4660c22fafdSGreg Ungerer "=m" (sc->sc_fpcntl[2])
4670c22fafdSGreg Ungerer : /* no inputs */
4680c22fafdSGreg Ungerer : "memory");
4690c22fafdSGreg Ungerer } else {
4700c22fafdSGreg Ungerer __asm__ volatile (".chip 68k/68881\n\t"
4710c22fafdSGreg Ungerer "fmovemx %%fp0-%%fp1,%0\n\t"
4720c22fafdSGreg Ungerer "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
4730c22fafdSGreg Ungerer ".chip 68k"
4740c22fafdSGreg Ungerer : "=m" (*sc->sc_fpregs),
4750c22fafdSGreg Ungerer "=m" (*sc->sc_fpcntl)
4760c22fafdSGreg Ungerer : /* no inputs */
4770c22fafdSGreg Ungerer : "memory");
4780c22fafdSGreg Ungerer }
4790c22fafdSGreg Ungerer }
4800c22fafdSGreg Ungerer }
4810c22fafdSGreg Ungerer
rt_save_fpu_state(struct ucontext __user * uc,struct pt_regs * regs)4820c22fafdSGreg Ungerer static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
4830c22fafdSGreg Ungerer {
4840c22fafdSGreg Ungerer unsigned char fpstate[FPCONTEXT_SIZE];
4850c22fafdSGreg Ungerer int context_size = CPU_IS_060 ? 8 : (CPU_IS_COLDFIRE ? 12 : 0);
4860c22fafdSGreg Ungerer int err = 0;
4870c22fafdSGreg Ungerer
4880c22fafdSGreg Ungerer if (FPU_IS_EMU) {
4890c22fafdSGreg Ungerer /* save fpu control register */
4900c22fafdSGreg Ungerer err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl,
4910c22fafdSGreg Ungerer current->thread.fpcntl, 12);
4920c22fafdSGreg Ungerer /* save all other fpu register */
4930c22fafdSGreg Ungerer err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
4940c22fafdSGreg Ungerer current->thread.fp, 96);
4950c22fafdSGreg Ungerer return err;
4960c22fafdSGreg Ungerer }
4970c22fafdSGreg Ungerer
4980c22fafdSGreg Ungerer if (CPU_IS_COLDFIRE) {
4990c22fafdSGreg Ungerer __asm__ volatile ("fsave %0" : : "m" (*fpstate) : "memory");
5000c22fafdSGreg Ungerer } else {
5010c22fafdSGreg Ungerer __asm__ volatile (".chip 68k/68881\n\t"
5020c22fafdSGreg Ungerer "fsave %0\n\t"
5030c22fafdSGreg Ungerer ".chip 68k"
5040c22fafdSGreg Ungerer : : "m" (*fpstate) : "memory");
5050c22fafdSGreg Ungerer }
5060c22fafdSGreg Ungerer
5070c22fafdSGreg Ungerer err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
5080c22fafdSGreg Ungerer if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
5090c22fafdSGreg Ungerer fpregset_t fpregs;
5100c22fafdSGreg Ungerer if (!(CPU_IS_060 || CPU_IS_COLDFIRE))
5110c22fafdSGreg Ungerer context_size = fpstate[1];
5120c22fafdSGreg Ungerer fpu_version = fpstate[0];
5134bb0bd81SAl Viro if (CPU_IS_020_OR_030 && !regs->stkadj &&
5140c22fafdSGreg Ungerer regs->vector >= (VEC_FPBRUC * 4) &&
5150c22fafdSGreg Ungerer regs->vector <= (VEC_FPNAN * 4)) {
5160c22fafdSGreg Ungerer /* Clear pending exception in 68882 idle frame */
5170c22fafdSGreg Ungerer if (*(unsigned short *) fpstate == 0x1f38)
5180c22fafdSGreg Ungerer fpstate[0x38] |= 1 << 3;
5190c22fafdSGreg Ungerer }
5200c22fafdSGreg Ungerer if (CPU_IS_COLDFIRE) {
5210c22fafdSGreg Ungerer __asm__ volatile ("fmovemd %%fp0-%%fp7,%0\n\t"
5220c22fafdSGreg Ungerer "fmovel %%fpcr,%1\n\t"
5230c22fafdSGreg Ungerer "fmovel %%fpsr,%2\n\t"
5240c22fafdSGreg Ungerer "fmovel %%fpiar,%3"
5250c22fafdSGreg Ungerer : "=m" (fpregs.f_fpregs[0]),
5260c22fafdSGreg Ungerer "=m" (fpregs.f_fpcntl[0]),
5270c22fafdSGreg Ungerer "=m" (fpregs.f_fpcntl[1]),
5280c22fafdSGreg Ungerer "=m" (fpregs.f_fpcntl[2])
5290c22fafdSGreg Ungerer : /* no inputs */
5300c22fafdSGreg Ungerer : "memory");
5310c22fafdSGreg Ungerer } else {
5320c22fafdSGreg Ungerer __asm__ volatile (".chip 68k/68881\n\t"
5330c22fafdSGreg Ungerer "fmovemx %%fp0-%%fp7,%0\n\t"
5340c22fafdSGreg Ungerer "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
5350c22fafdSGreg Ungerer ".chip 68k"
5360c22fafdSGreg Ungerer : "=m" (*fpregs.f_fpregs),
5370c22fafdSGreg Ungerer "=m" (*fpregs.f_fpcntl)
5380c22fafdSGreg Ungerer : /* no inputs */
5390c22fafdSGreg Ungerer : "memory");
5400c22fafdSGreg Ungerer }
5410c22fafdSGreg Ungerer err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
5420c22fafdSGreg Ungerer sizeof(fpregs));
5430c22fafdSGreg Ungerer }
5440c22fafdSGreg Ungerer if (context_size)
5450c22fafdSGreg Ungerer err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4,
5460c22fafdSGreg Ungerer context_size);
5470c22fafdSGreg Ungerer return err;
5480c22fafdSGreg Ungerer }
5490c22fafdSGreg Ungerer
5500c22fafdSGreg Ungerer #else /* CONFIG_FPU */
5510c22fafdSGreg Ungerer
5520c22fafdSGreg Ungerer /*
5530c22fafdSGreg Ungerer * For the case with no FPU configured these all do nothing.
5540c22fafdSGreg Ungerer */
restore_fpu_state(struct sigcontext * sc)5550c22fafdSGreg Ungerer static inline int restore_fpu_state(struct sigcontext *sc)
5560c22fafdSGreg Ungerer {
5570c22fafdSGreg Ungerer return 0;
5580c22fafdSGreg Ungerer }
5590c22fafdSGreg Ungerer
rt_restore_fpu_state(struct ucontext __user * uc)5600c22fafdSGreg Ungerer static inline int rt_restore_fpu_state(struct ucontext __user *uc)
5610c22fafdSGreg Ungerer {
5620c22fafdSGreg Ungerer return 0;
5630c22fafdSGreg Ungerer }
5640c22fafdSGreg Ungerer
save_fpu_state(struct sigcontext * sc,struct pt_regs * regs)5650c22fafdSGreg Ungerer static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
5660c22fafdSGreg Ungerer {
5670c22fafdSGreg Ungerer }
5680c22fafdSGreg Ungerer
rt_save_fpu_state(struct ucontext __user * uc,struct pt_regs * regs)5690c22fafdSGreg Ungerer static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
5700c22fafdSGreg Ungerer {
5710c22fafdSGreg Ungerer return 0;
5720c22fafdSGreg Ungerer }
5730c22fafdSGreg Ungerer
5740c22fafdSGreg Ungerer #endif /* CONFIG_FPU */
5750c22fafdSGreg Ungerer
siginfo_build_tests(void)5764be33329SEric W. Biederman static inline void siginfo_build_tests(void)
5774be33329SEric W. Biederman {
5784eee57d6SGeert Uytterhoeven /*
5794eee57d6SGeert Uytterhoeven * This needs to be tested on m68k as it has a lesser
5804eee57d6SGeert Uytterhoeven * alignment requirement than x86 and that can cause surprises.
5814be33329SEric W. Biederman */
5824be33329SEric W. Biederman
5834be33329SEric W. Biederman /* This is part of the ABI and can never change in size: */
5844be33329SEric W. Biederman BUILD_BUG_ON(sizeof(siginfo_t) != 128);
5854be33329SEric W. Biederman
5864eee57d6SGeert Uytterhoeven /* Ensure the known fields never change in location */
5874be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_signo) != 0);
5884be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_errno) != 4);
5894be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_code) != 8);
5904be33329SEric W. Biederman
5914be33329SEric W. Biederman /* _kill */
5924eee57d6SGeert Uytterhoeven BUILD_BUG_ON(offsetof(siginfo_t, si_pid) != 0x0c);
5934be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_uid) != 0x10);
5944be33329SEric W. Biederman
5954be33329SEric W. Biederman /* _timer */
5964eee57d6SGeert Uytterhoeven BUILD_BUG_ON(offsetof(siginfo_t, si_tid) != 0x0c);
5974be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_overrun) != 0x10);
5984be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_value) != 0x14);
5994be33329SEric W. Biederman
6004be33329SEric W. Biederman /* _rt */
6014eee57d6SGeert Uytterhoeven BUILD_BUG_ON(offsetof(siginfo_t, si_pid) != 0x0c);
6024be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_uid) != 0x10);
6034be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_value) != 0x14);
6044be33329SEric W. Biederman
6054be33329SEric W. Biederman /* _sigchld */
6064eee57d6SGeert Uytterhoeven BUILD_BUG_ON(offsetof(siginfo_t, si_pid) != 0x0c);
6074be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_uid) != 0x10);
6084be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_status) != 0x14);
6094be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_utime) != 0x18);
6104eee57d6SGeert Uytterhoeven BUILD_BUG_ON(offsetof(siginfo_t, si_stime) != 0x1c);
6114be33329SEric W. Biederman
6124be33329SEric W. Biederman /* _sigfault */
6134eee57d6SGeert Uytterhoeven BUILD_BUG_ON(offsetof(siginfo_t, si_addr) != 0x0c);
6144be33329SEric W. Biederman
6154be33329SEric W. Biederman /* _sigfault._mcerr */
6164be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_addr_lsb) != 0x10);
6174be33329SEric W. Biederman
6184be33329SEric W. Biederman /* _sigfault._addr_bnd */
6194be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_lower) != 0x12);
6204be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_upper) != 0x16);
6214be33329SEric W. Biederman
6224be33329SEric W. Biederman /* _sigfault._addr_pkey */
6234be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_pkey) != 0x12);
6244be33329SEric W. Biederman
625fb6cc127SMarco Elver /* _sigfault._perf */
6260683b531SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_perf_data) != 0x10);
6270683b531SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_perf_type) != 0x14);
62878ed93d7SMarco Elver BUILD_BUG_ON(offsetof(siginfo_t, si_perf_flags) != 0x18);
629fb6cc127SMarco Elver
6304be33329SEric W. Biederman /* _sigpoll */
6314eee57d6SGeert Uytterhoeven BUILD_BUG_ON(offsetof(siginfo_t, si_band) != 0x0c);
6324be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_fd) != 0x10);
6334be33329SEric W. Biederman
6344be33329SEric W. Biederman /* _sigsys */
6354eee57d6SGeert Uytterhoeven BUILD_BUG_ON(offsetof(siginfo_t, si_call_addr) != 0x0c);
6364be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_syscall) != 0x10);
6374be33329SEric W. Biederman BUILD_BUG_ON(offsetof(siginfo_t, si_arch) != 0x14);
6384be33329SEric W. Biederman
6394be33329SEric W. Biederman /* any new si_fields should be added here */
6404be33329SEric W. Biederman }
6414be33329SEric W. Biederman
mangle_kernel_stack(struct pt_regs * regs,int formatvec,void __user * fp)6420c22fafdSGreg Ungerer static int mangle_kernel_stack(struct pt_regs *regs, int formatvec,
6430c22fafdSGreg Ungerer void __user *fp)
6440c22fafdSGreg Ungerer {
6450d20abdeSAl Viro int extra = frame_extra_sizes(formatvec >> 12);
6460d20abdeSAl Viro char buf[sizeof_field(struct frame, un)];
6470d20abdeSAl Viro
6480d20abdeSAl Viro if (extra < 0) {
6490c22fafdSGreg Ungerer /*
6500c22fafdSGreg Ungerer * user process trying to return with weird frame format
6510c22fafdSGreg Ungerer */
6527c79e1eeSGeert Uytterhoeven pr_debug("user process returning with weird frame format\n");
6530d20abdeSAl Viro return -1;
6540c22fafdSGreg Ungerer }
6550d20abdeSAl Viro if (extra && copy_from_user(buf, fp, extra))
6560d20abdeSAl Viro return -1;
6570c22fafdSGreg Ungerer regs->format = formatvec >> 12;
6580c22fafdSGreg Ungerer regs->vector = formatvec & 0xfff;
6590d20abdeSAl Viro if (extra) {
6600d20abdeSAl Viro void *p = (struct switch_stack *)regs - 1;
6610d20abdeSAl Viro struct frame *new = (void *)regs - extra;
6620d20abdeSAl Viro int size = sizeof(struct pt_regs)+sizeof(struct switch_stack);
6630c22fafdSGreg Ungerer
6640d20abdeSAl Viro memmove(p - extra, p, size);
6650d20abdeSAl Viro memcpy(p - extra + size, buf, extra);
6660d20abdeSAl Viro current->thread.esp0 = (unsigned long)&new->ptregs;
6670d20abdeSAl Viro #ifdef CONFIG_M68040
6680d20abdeSAl Viro /* on 68040 complete pending writebacks if any */
6690d20abdeSAl Viro if (new->ptregs.format == 7) // bus error frame
6700d20abdeSAl Viro berr_040cleanup(new);
6710c22fafdSGreg Ungerer #endif
6720c22fafdSGreg Ungerer }
6730d20abdeSAl Viro return extra;
6740c22fafdSGreg Ungerer }
6750c22fafdSGreg Ungerer
6760c22fafdSGreg Ungerer static inline int
restore_sigcontext(struct pt_regs * regs,struct sigcontext __user * usc,void __user * fp)6770c22fafdSGreg Ungerer restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp)
6780c22fafdSGreg Ungerer {
6790c22fafdSGreg Ungerer int formatvec;
6800c22fafdSGreg Ungerer struct sigcontext context;
6810c22fafdSGreg Ungerer
6824be33329SEric W. Biederman siginfo_build_tests();
6834be33329SEric W. Biederman
6840c22fafdSGreg Ungerer /* Always make any pending restarted system calls return -EINTR */
685f56141e3SAndy Lutomirski current->restart_block.fn = do_no_restart_syscall;
6860c22fafdSGreg Ungerer
6870c22fafdSGreg Ungerer /* get previous context */
6880c22fafdSGreg Ungerer if (copy_from_user(&context, usc, sizeof(context)))
6890d20abdeSAl Viro return -1;
6900c22fafdSGreg Ungerer
6910c22fafdSGreg Ungerer /* restore passed registers */
6920c22fafdSGreg Ungerer regs->d0 = context.sc_d0;
6930c22fafdSGreg Ungerer regs->d1 = context.sc_d1;
6940c22fafdSGreg Ungerer regs->a0 = context.sc_a0;
6950c22fafdSGreg Ungerer regs->a1 = context.sc_a1;
6960c22fafdSGreg Ungerer regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
6970c22fafdSGreg Ungerer regs->pc = context.sc_pc;
6980c22fafdSGreg Ungerer regs->orig_d0 = -1; /* disable syscall checks */
6990c22fafdSGreg Ungerer wrusp(context.sc_usp);
7000c22fafdSGreg Ungerer formatvec = context.sc_formatvec;
7010c22fafdSGreg Ungerer
7020d20abdeSAl Viro if (restore_fpu_state(&context))
7030d20abdeSAl Viro return -1;
7040c22fafdSGreg Ungerer
7050d20abdeSAl Viro return mangle_kernel_stack(regs, formatvec, fp);
7060c22fafdSGreg Ungerer }
7070c22fafdSGreg Ungerer
7080c22fafdSGreg Ungerer static inline int
rt_restore_ucontext(struct pt_regs * regs,struct switch_stack * sw,struct ucontext __user * uc)7090c22fafdSGreg Ungerer rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
7100c22fafdSGreg Ungerer struct ucontext __user *uc)
7110c22fafdSGreg Ungerer {
7120c22fafdSGreg Ungerer int temp;
7130c22fafdSGreg Ungerer greg_t __user *gregs = uc->uc_mcontext.gregs;
7140c22fafdSGreg Ungerer unsigned long usp;
7150c22fafdSGreg Ungerer int err;
7160c22fafdSGreg Ungerer
7170c22fafdSGreg Ungerer /* Always make any pending restarted system calls return -EINTR */
718f56141e3SAndy Lutomirski current->restart_block.fn = do_no_restart_syscall;
7190c22fafdSGreg Ungerer
7200c22fafdSGreg Ungerer err = __get_user(temp, &uc->uc_mcontext.version);
7210c22fafdSGreg Ungerer if (temp != MCONTEXT_VERSION)
7220d20abdeSAl Viro return -1;
7230c22fafdSGreg Ungerer /* restore passed registers */
7240c22fafdSGreg Ungerer err |= __get_user(regs->d0, &gregs[0]);
7250c22fafdSGreg Ungerer err |= __get_user(regs->d1, &gregs[1]);
7260c22fafdSGreg Ungerer err |= __get_user(regs->d2, &gregs[2]);
7270c22fafdSGreg Ungerer err |= __get_user(regs->d3, &gregs[3]);
7280c22fafdSGreg Ungerer err |= __get_user(regs->d4, &gregs[4]);
7290c22fafdSGreg Ungerer err |= __get_user(regs->d5, &gregs[5]);
7300c22fafdSGreg Ungerer err |= __get_user(sw->d6, &gregs[6]);
7310c22fafdSGreg Ungerer err |= __get_user(sw->d7, &gregs[7]);
7320c22fafdSGreg Ungerer err |= __get_user(regs->a0, &gregs[8]);
7330c22fafdSGreg Ungerer err |= __get_user(regs->a1, &gregs[9]);
7340c22fafdSGreg Ungerer err |= __get_user(regs->a2, &gregs[10]);
7350c22fafdSGreg Ungerer err |= __get_user(sw->a3, &gregs[11]);
7360c22fafdSGreg Ungerer err |= __get_user(sw->a4, &gregs[12]);
7370c22fafdSGreg Ungerer err |= __get_user(sw->a5, &gregs[13]);
7380c22fafdSGreg Ungerer err |= __get_user(sw->a6, &gregs[14]);
7390c22fafdSGreg Ungerer err |= __get_user(usp, &gregs[15]);
7400c22fafdSGreg Ungerer wrusp(usp);
7410c22fafdSGreg Ungerer err |= __get_user(regs->pc, &gregs[16]);
7420c22fafdSGreg Ungerer err |= __get_user(temp, &gregs[17]);
7430c22fafdSGreg Ungerer regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
7440c22fafdSGreg Ungerer regs->orig_d0 = -1; /* disable syscall checks */
7450c22fafdSGreg Ungerer err |= __get_user(temp, &uc->uc_formatvec);
7460c22fafdSGreg Ungerer
7470c22fafdSGreg Ungerer err |= rt_restore_fpu_state(uc);
74808d4f653SAl Viro err |= restore_altstack(&uc->uc_stack);
7490c22fafdSGreg Ungerer
75008d4f653SAl Viro if (err)
7510d20abdeSAl Viro return -1;
7520c22fafdSGreg Ungerer
7530d20abdeSAl Viro return mangle_kernel_stack(regs, temp, &uc->uc_extra);
7540c22fafdSGreg Ungerer }
7550c22fafdSGreg Ungerer
do_sigreturn(struct pt_regs * regs,struct switch_stack * sw)7560d20abdeSAl Viro asmlinkage void *do_sigreturn(struct pt_regs *regs, struct switch_stack *sw)
7570c22fafdSGreg Ungerer {
7580c22fafdSGreg Ungerer unsigned long usp = rdusp();
7590c22fafdSGreg Ungerer struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
7600c22fafdSGreg Ungerer sigset_t set;
7610d20abdeSAl Viro int size;
7620c22fafdSGreg Ungerer
76396d4f267SLinus Torvalds if (!access_ok(frame, sizeof(*frame)))
7640c22fafdSGreg Ungerer goto badframe;
7650c22fafdSGreg Ungerer if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
7660c22fafdSGreg Ungerer (_NSIG_WORDS > 1 &&
7670c22fafdSGreg Ungerer __copy_from_user(&set.sig[1], &frame->extramask,
7680c22fafdSGreg Ungerer sizeof(frame->extramask))))
7690c22fafdSGreg Ungerer goto badframe;
7700c22fafdSGreg Ungerer
77143a35995SMatt Fleming set_current_blocked(&set);
7720c22fafdSGreg Ungerer
7730d20abdeSAl Viro size = restore_sigcontext(regs, &frame->sc, frame + 1);
7740d20abdeSAl Viro if (size < 0)
7750c22fafdSGreg Ungerer goto badframe;
7760d20abdeSAl Viro return (void *)sw - size;
7770c22fafdSGreg Ungerer
7780c22fafdSGreg Ungerer badframe:
7793cf5d076SEric W. Biederman force_sig(SIGSEGV);
7800d20abdeSAl Viro return sw;
7810c22fafdSGreg Ungerer }
7820c22fafdSGreg Ungerer
do_rt_sigreturn(struct pt_regs * regs,struct switch_stack * sw)7830d20abdeSAl Viro asmlinkage void *do_rt_sigreturn(struct pt_regs *regs, struct switch_stack *sw)
7840c22fafdSGreg Ungerer {
7850c22fafdSGreg Ungerer unsigned long usp = rdusp();
7860c22fafdSGreg Ungerer struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
7870c22fafdSGreg Ungerer sigset_t set;
7880d20abdeSAl Viro int size;
7890c22fafdSGreg Ungerer
79096d4f267SLinus Torvalds if (!access_ok(frame, sizeof(*frame)))
7910c22fafdSGreg Ungerer goto badframe;
7920c22fafdSGreg Ungerer if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
7930c22fafdSGreg Ungerer goto badframe;
7940c22fafdSGreg Ungerer
79543a35995SMatt Fleming set_current_blocked(&set);
7960c22fafdSGreg Ungerer
7970d20abdeSAl Viro size = rt_restore_ucontext(regs, sw, &frame->uc);
7980d20abdeSAl Viro if (size < 0)
7990c22fafdSGreg Ungerer goto badframe;
8000d20abdeSAl Viro return (void *)sw - size;
8010c22fafdSGreg Ungerer
8020c22fafdSGreg Ungerer badframe:
8033cf5d076SEric W. Biederman force_sig(SIGSEGV);
8040d20abdeSAl Viro return sw;
8050c22fafdSGreg Ungerer }
8060c22fafdSGreg Ungerer
rte_regs(struct pt_regs * regs)8074bb0bd81SAl Viro static inline struct pt_regs *rte_regs(struct pt_regs *regs)
8084bb0bd81SAl Viro {
8094bb0bd81SAl Viro return (void *)regs + regs->stkadj;
8104bb0bd81SAl Viro }
8114bb0bd81SAl Viro
setup_sigcontext(struct sigcontext * sc,struct pt_regs * regs,unsigned long mask)8120c22fafdSGreg Ungerer static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
8130c22fafdSGreg Ungerer unsigned long mask)
8140c22fafdSGreg Ungerer {
8154bb0bd81SAl Viro struct pt_regs *tregs = rte_regs(regs);
8160c22fafdSGreg Ungerer sc->sc_mask = mask;
8170c22fafdSGreg Ungerer sc->sc_usp = rdusp();
8180c22fafdSGreg Ungerer sc->sc_d0 = regs->d0;
8190c22fafdSGreg Ungerer sc->sc_d1 = regs->d1;
8200c22fafdSGreg Ungerer sc->sc_a0 = regs->a0;
8210c22fafdSGreg Ungerer sc->sc_a1 = regs->a1;
8224bb0bd81SAl Viro sc->sc_sr = tregs->sr;
8234bb0bd81SAl Viro sc->sc_pc = tregs->pc;
8244bb0bd81SAl Viro sc->sc_formatvec = tregs->format << 12 | tregs->vector;
8250c22fafdSGreg Ungerer save_a5_state(sc, regs);
8260c22fafdSGreg Ungerer save_fpu_state(sc, regs);
8270c22fafdSGreg Ungerer }
8280c22fafdSGreg Ungerer
rt_setup_ucontext(struct ucontext __user * uc,struct pt_regs * regs)8290c22fafdSGreg Ungerer static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
8300c22fafdSGreg Ungerer {
8310c22fafdSGreg Ungerer struct switch_stack *sw = (struct switch_stack *)regs - 1;
8324bb0bd81SAl Viro struct pt_regs *tregs = rte_regs(regs);
8330c22fafdSGreg Ungerer greg_t __user *gregs = uc->uc_mcontext.gregs;
8340c22fafdSGreg Ungerer int err = 0;
8350c22fafdSGreg Ungerer
8360c22fafdSGreg Ungerer err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
8370c22fafdSGreg Ungerer err |= __put_user(regs->d0, &gregs[0]);
8380c22fafdSGreg Ungerer err |= __put_user(regs->d1, &gregs[1]);
8390c22fafdSGreg Ungerer err |= __put_user(regs->d2, &gregs[2]);
8400c22fafdSGreg Ungerer err |= __put_user(regs->d3, &gregs[3]);
8410c22fafdSGreg Ungerer err |= __put_user(regs->d4, &gregs[4]);
8420c22fafdSGreg Ungerer err |= __put_user(regs->d5, &gregs[5]);
8430c22fafdSGreg Ungerer err |= __put_user(sw->d6, &gregs[6]);
8440c22fafdSGreg Ungerer err |= __put_user(sw->d7, &gregs[7]);
8450c22fafdSGreg Ungerer err |= __put_user(regs->a0, &gregs[8]);
8460c22fafdSGreg Ungerer err |= __put_user(regs->a1, &gregs[9]);
8470c22fafdSGreg Ungerer err |= __put_user(regs->a2, &gregs[10]);
8480c22fafdSGreg Ungerer err |= __put_user(sw->a3, &gregs[11]);
8490c22fafdSGreg Ungerer err |= __put_user(sw->a4, &gregs[12]);
8500c22fafdSGreg Ungerer err |= __put_user(sw->a5, &gregs[13]);
8510c22fafdSGreg Ungerer err |= __put_user(sw->a6, &gregs[14]);
8520c22fafdSGreg Ungerer err |= __put_user(rdusp(), &gregs[15]);
8534bb0bd81SAl Viro err |= __put_user(tregs->pc, &gregs[16]);
8544bb0bd81SAl Viro err |= __put_user(tregs->sr, &gregs[17]);
8554bb0bd81SAl Viro err |= __put_user((tregs->format << 12) | tregs->vector, &uc->uc_formatvec);
8560c22fafdSGreg Ungerer err |= rt_save_fpu_state(uc, regs);
8570c22fafdSGreg Ungerer return err;
8580c22fafdSGreg Ungerer }
8590c22fafdSGreg Ungerer
8600c22fafdSGreg Ungerer static inline void __user *
get_sigframe(struct ksignal * ksig,struct pt_regs * tregs,size_t frame_size)861*b845b574SFinn Thain get_sigframe(struct ksignal *ksig, struct pt_regs *tregs, size_t frame_size)
8620c22fafdSGreg Ungerer {
86336992f28SRichard Weinberger unsigned long usp = sigsp(rdusp(), ksig);
864*b845b574SFinn Thain unsigned long gap = 0;
8650c22fafdSGreg Ungerer
866*b845b574SFinn Thain if (CPU_IS_020_OR_030 && tregs->format == 0xb) {
867*b845b574SFinn Thain /* USP is unreliable so use worst-case value */
868*b845b574SFinn Thain gap = 256;
869*b845b574SFinn Thain }
870*b845b574SFinn Thain
871*b845b574SFinn Thain return (void __user *)((usp - gap - frame_size) & -8UL);
8720c22fafdSGreg Ungerer }
8730c22fafdSGreg Ungerer
setup_frame(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)8740d97500dSRichard Weinberger static int setup_frame(struct ksignal *ksig, sigset_t *set,
8750d97500dSRichard Weinberger struct pt_regs *regs)
8760c22fafdSGreg Ungerer {
8770c22fafdSGreg Ungerer struct sigframe __user *frame;
8784bb0bd81SAl Viro struct pt_regs *tregs = rte_regs(regs);
8794bb0bd81SAl Viro int fsize = frame_extra_sizes(tregs->format);
8800c22fafdSGreg Ungerer struct sigcontext context;
8810d97500dSRichard Weinberger int err = 0, sig = ksig->sig;
8820c22fafdSGreg Ungerer
8830c22fafdSGreg Ungerer if (fsize < 0) {
8847c79e1eeSGeert Uytterhoeven pr_debug("setup_frame: Unknown frame format %#x\n",
8854bb0bd81SAl Viro tregs->format);
8860d97500dSRichard Weinberger return -EFAULT;
8870c22fafdSGreg Ungerer }
8880c22fafdSGreg Ungerer
889*b845b574SFinn Thain frame = get_sigframe(ksig, tregs, sizeof(*frame) + fsize);
8900c22fafdSGreg Ungerer
8910c22fafdSGreg Ungerer if (fsize)
8920c22fafdSGreg Ungerer err |= copy_to_user (frame + 1, regs + 1, fsize);
8930c22fafdSGreg Ungerer
894a0075cd1SRichard Weinberger err |= __put_user(sig, &frame->sig);
8950c22fafdSGreg Ungerer
8964bb0bd81SAl Viro err |= __put_user(tregs->vector, &frame->code);
8970c22fafdSGreg Ungerer err |= __put_user(&frame->sc, &frame->psc);
8980c22fafdSGreg Ungerer
8990c22fafdSGreg Ungerer if (_NSIG_WORDS > 1)
9000c22fafdSGreg Ungerer err |= copy_to_user(frame->extramask, &set->sig[1],
9010c22fafdSGreg Ungerer sizeof(frame->extramask));
9020c22fafdSGreg Ungerer
9030c22fafdSGreg Ungerer setup_sigcontext(&context, regs, set->sig[0]);
9040c22fafdSGreg Ungerer err |= copy_to_user (&frame->sc, &context, sizeof(context));
9050c22fafdSGreg Ungerer
9060c22fafdSGreg Ungerer /* Set up to return from userspace. */
9070c22fafdSGreg Ungerer #ifdef CONFIG_MMU
9080c22fafdSGreg Ungerer err |= __put_user(frame->retcode, &frame->pretcode);
9090c22fafdSGreg Ungerer /* moveq #,d0; trap #0 */
9100c22fafdSGreg Ungerer err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
9110c22fafdSGreg Ungerer (long __user *)(frame->retcode));
9120c22fafdSGreg Ungerer #else
91300696747SGreg Ungerer err |= __put_user((long) ret_from_user_signal,
91400696747SGreg Ungerer (long __user *) &frame->pretcode);
9150c22fafdSGreg Ungerer #endif
9160c22fafdSGreg Ungerer
9170c22fafdSGreg Ungerer if (err)
9180d97500dSRichard Weinberger return -EFAULT;
9190c22fafdSGreg Ungerer
9200c22fafdSGreg Ungerer push_cache ((unsigned long) &frame->retcode);
9210c22fafdSGreg Ungerer
9220c22fafdSGreg Ungerer /*
9230c22fafdSGreg Ungerer * This is subtle; if we build more than one sigframe, all but the
9240c22fafdSGreg Ungerer * first one will see frame format 0 and have fsize == 0, so we won't
9250c22fafdSGreg Ungerer * screw stkadj.
9260c22fafdSGreg Ungerer */
9274bb0bd81SAl Viro if (fsize) {
9280c22fafdSGreg Ungerer regs->stkadj = fsize;
9294bb0bd81SAl Viro tregs = rte_regs(regs);
9307c79e1eeSGeert Uytterhoeven pr_debug("Performing stackadjust=%04lx\n", regs->stkadj);
9310c22fafdSGreg Ungerer tregs->vector = 0;
9320c22fafdSGreg Ungerer tregs->format = 0;
9330c22fafdSGreg Ungerer tregs->sr = regs->sr;
9340c22fafdSGreg Ungerer }
9354bb0bd81SAl Viro
9364bb0bd81SAl Viro /*
9374bb0bd81SAl Viro * Set up registers for signal handler. All the state we are about
9384bb0bd81SAl Viro * to destroy is successfully copied to sigframe.
9394bb0bd81SAl Viro */
9404bb0bd81SAl Viro wrusp ((unsigned long) frame);
9414bb0bd81SAl Viro tregs->pc = (unsigned long) ksig->ka.sa.sa_handler;
9424bb0bd81SAl Viro adjustformat(regs);
9434bb0bd81SAl Viro
9440c22fafdSGreg Ungerer return 0;
9450c22fafdSGreg Ungerer }
9460c22fafdSGreg Ungerer
setup_rt_frame(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)9470d97500dSRichard Weinberger static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
9480d97500dSRichard Weinberger struct pt_regs *regs)
9490c22fafdSGreg Ungerer {
9500c22fafdSGreg Ungerer struct rt_sigframe __user *frame;
9514bb0bd81SAl Viro struct pt_regs *tregs = rte_regs(regs);
9524bb0bd81SAl Viro int fsize = frame_extra_sizes(tregs->format);
9530d97500dSRichard Weinberger int err = 0, sig = ksig->sig;
9540c22fafdSGreg Ungerer
9550c22fafdSGreg Ungerer if (fsize < 0) {
9567c79e1eeSGeert Uytterhoeven pr_debug("setup_frame: Unknown frame format %#x\n",
9570c22fafdSGreg Ungerer regs->format);
9580d97500dSRichard Weinberger return -EFAULT;
9590c22fafdSGreg Ungerer }
9600c22fafdSGreg Ungerer
961*b845b574SFinn Thain frame = get_sigframe(ksig, tregs, sizeof(*frame));
9620c22fafdSGreg Ungerer
9630c22fafdSGreg Ungerer if (fsize)
9640c22fafdSGreg Ungerer err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
9650c22fafdSGreg Ungerer
966a0075cd1SRichard Weinberger err |= __put_user(sig, &frame->sig);
9670c22fafdSGreg Ungerer err |= __put_user(&frame->info, &frame->pinfo);
9680c22fafdSGreg Ungerer err |= __put_user(&frame->uc, &frame->puc);
9690d97500dSRichard Weinberger err |= copy_siginfo_to_user(&frame->info, &ksig->info);
9700c22fafdSGreg Ungerer
9710c22fafdSGreg Ungerer /* Create the ucontext. */
9720c22fafdSGreg Ungerer err |= __put_user(0, &frame->uc.uc_flags);
9730c22fafdSGreg Ungerer err |= __put_user(NULL, &frame->uc.uc_link);
97408d4f653SAl Viro err |= __save_altstack(&frame->uc.uc_stack, rdusp());
9750c22fafdSGreg Ungerer err |= rt_setup_ucontext(&frame->uc, regs);
9760c22fafdSGreg Ungerer err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
9770c22fafdSGreg Ungerer
9780c22fafdSGreg Ungerer /* Set up to return from userspace. */
9790c22fafdSGreg Ungerer #ifdef CONFIG_MMU
9800c22fafdSGreg Ungerer err |= __put_user(frame->retcode, &frame->pretcode);
9810c22fafdSGreg Ungerer #ifdef __mcoldfire__
9820c22fafdSGreg Ungerer /* movel #__NR_rt_sigreturn,d0; trap #0 */
9830c22fafdSGreg Ungerer err |= __put_user(0x203c0000, (long __user *)(frame->retcode + 0));
9840c22fafdSGreg Ungerer err |= __put_user(0x00004e40 + (__NR_rt_sigreturn << 16),
9850c22fafdSGreg Ungerer (long __user *)(frame->retcode + 4));
9860c22fafdSGreg Ungerer #else
9870c22fafdSGreg Ungerer /* moveq #,d0; notb d0; trap #0 */
9880c22fafdSGreg Ungerer err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
9890c22fafdSGreg Ungerer (long __user *)(frame->retcode + 0));
9900c22fafdSGreg Ungerer err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4));
9910c22fafdSGreg Ungerer #endif
9920c22fafdSGreg Ungerer #else
99300696747SGreg Ungerer err |= __put_user((long) ret_from_user_rt_signal,
99400696747SGreg Ungerer (long __user *) &frame->pretcode);
9950c22fafdSGreg Ungerer #endif /* CONFIG_MMU */
9960c22fafdSGreg Ungerer
9970c22fafdSGreg Ungerer if (err)
9980d97500dSRichard Weinberger return -EFAULT;
9990c22fafdSGreg Ungerer
10000c22fafdSGreg Ungerer push_cache ((unsigned long) &frame->retcode);
10010c22fafdSGreg Ungerer
10020c22fafdSGreg Ungerer /*
10030c22fafdSGreg Ungerer * This is subtle; if we build more than one sigframe, all but the
10040c22fafdSGreg Ungerer * first one will see frame format 0 and have fsize == 0, so we won't
10050c22fafdSGreg Ungerer * screw stkadj.
10060c22fafdSGreg Ungerer */
10074bb0bd81SAl Viro if (fsize) {
10080c22fafdSGreg Ungerer regs->stkadj = fsize;
10094bb0bd81SAl Viro tregs = rte_regs(regs);
10107c79e1eeSGeert Uytterhoeven pr_debug("Performing stackadjust=%04lx\n", regs->stkadj);
10110c22fafdSGreg Ungerer tregs->vector = 0;
10120c22fafdSGreg Ungerer tregs->format = 0;
10130c22fafdSGreg Ungerer tregs->sr = regs->sr;
10140c22fafdSGreg Ungerer }
10154bb0bd81SAl Viro
10164bb0bd81SAl Viro /*
10174bb0bd81SAl Viro * Set up registers for signal handler. All the state we are about
10184bb0bd81SAl Viro * to destroy is successfully copied to sigframe.
10194bb0bd81SAl Viro */
10204bb0bd81SAl Viro wrusp ((unsigned long) frame);
10214bb0bd81SAl Viro tregs->pc = (unsigned long) ksig->ka.sa.sa_handler;
10224bb0bd81SAl Viro adjustformat(regs);
10230c22fafdSGreg Ungerer return 0;
10240c22fafdSGreg Ungerer }
10250c22fafdSGreg Ungerer
10260c22fafdSGreg Ungerer static inline void
handle_restart(struct pt_regs * regs,struct k_sigaction * ka,int has_handler)10270c22fafdSGreg Ungerer handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
10280c22fafdSGreg Ungerer {
10290c22fafdSGreg Ungerer switch (regs->d0) {
10300c22fafdSGreg Ungerer case -ERESTARTNOHAND:
10310c22fafdSGreg Ungerer if (!has_handler)
10320c22fafdSGreg Ungerer goto do_restart;
10330c22fafdSGreg Ungerer regs->d0 = -EINTR;
10340c22fafdSGreg Ungerer break;
10350c22fafdSGreg Ungerer
10360c22fafdSGreg Ungerer case -ERESTART_RESTARTBLOCK:
10370c22fafdSGreg Ungerer if (!has_handler) {
10380c22fafdSGreg Ungerer regs->d0 = __NR_restart_syscall;
10390c22fafdSGreg Ungerer regs->pc -= 2;
10400c22fafdSGreg Ungerer break;
10410c22fafdSGreg Ungerer }
10420c22fafdSGreg Ungerer regs->d0 = -EINTR;
10430c22fafdSGreg Ungerer break;
10440c22fafdSGreg Ungerer
10450c22fafdSGreg Ungerer case -ERESTARTSYS:
10460c22fafdSGreg Ungerer if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
10470c22fafdSGreg Ungerer regs->d0 = -EINTR;
10480c22fafdSGreg Ungerer break;
10490c22fafdSGreg Ungerer }
1050df561f66SGustavo A. R. Silva fallthrough;
10510c22fafdSGreg Ungerer case -ERESTARTNOINTR:
10520c22fafdSGreg Ungerer do_restart:
10530c22fafdSGreg Ungerer regs->d0 = regs->orig_d0;
10540c22fafdSGreg Ungerer regs->pc -= 2;
10550c22fafdSGreg Ungerer break;
10560c22fafdSGreg Ungerer }
10570c22fafdSGreg Ungerer }
10580c22fafdSGreg Ungerer
10590c22fafdSGreg Ungerer /*
10600c22fafdSGreg Ungerer * OK, we're invoking a handler
10610c22fafdSGreg Ungerer */
10620c22fafdSGreg Ungerer static void
handle_signal(struct ksignal * ksig,struct pt_regs * regs)10630d97500dSRichard Weinberger handle_signal(struct ksignal *ksig, struct pt_regs *regs)
10640c22fafdSGreg Ungerer {
1065b7f9a11aSAl Viro sigset_t *oldset = sigmask_to_save();
10660c22fafdSGreg Ungerer int err;
10670c22fafdSGreg Ungerer /* are we from a system call? */
10680c22fafdSGreg Ungerer if (regs->orig_d0 >= 0)
10690c22fafdSGreg Ungerer /* If so, check system call restarting.. */
10700d97500dSRichard Weinberger handle_restart(regs, &ksig->ka, 1);
10710c22fafdSGreg Ungerer
10720c22fafdSGreg Ungerer /* set up the stack frame */
10730d97500dSRichard Weinberger if (ksig->ka.sa.sa_flags & SA_SIGINFO)
10740d97500dSRichard Weinberger err = setup_rt_frame(ksig, oldset, regs);
10750c22fafdSGreg Ungerer else
10760d97500dSRichard Weinberger err = setup_frame(ksig, oldset, regs);
10770c22fafdSGreg Ungerer
10780d97500dSRichard Weinberger signal_setup_done(err, ksig, 0);
10790c22fafdSGreg Ungerer
10800c22fafdSGreg Ungerer if (test_thread_flag(TIF_DELAYED_TRACE)) {
10810c22fafdSGreg Ungerer regs->sr &= ~0x8000;
10820c22fafdSGreg Ungerer send_sig(SIGTRAP, current, 1);
10830c22fafdSGreg Ungerer }
10840c22fafdSGreg Ungerer }
10850c22fafdSGreg Ungerer
10860c22fafdSGreg Ungerer /*
10870c22fafdSGreg Ungerer * Note that 'init' is a special process: it doesn't get signals it doesn't
10880c22fafdSGreg Ungerer * want to handle. Thus you cannot kill init even with a SIGKILL even by
10890c22fafdSGreg Ungerer * mistake.
10900c22fafdSGreg Ungerer */
do_signal(struct pt_regs * regs)1091a54f1655SAl Viro static void do_signal(struct pt_regs *regs)
10920c22fafdSGreg Ungerer {
10930d97500dSRichard Weinberger struct ksignal ksig;
10940c22fafdSGreg Ungerer
10950c22fafdSGreg Ungerer current->thread.esp0 = (unsigned long) regs;
10960c22fafdSGreg Ungerer
10970d97500dSRichard Weinberger if (get_signal(&ksig)) {
10980c22fafdSGreg Ungerer /* Whee! Actually deliver the signal. */
10990d97500dSRichard Weinberger handle_signal(&ksig, regs);
11000c22fafdSGreg Ungerer return;
11010c22fafdSGreg Ungerer }
11020c22fafdSGreg Ungerer
11030c22fafdSGreg Ungerer /* Did we come from a system call? */
11040c22fafdSGreg Ungerer if (regs->orig_d0 >= 0)
11050c22fafdSGreg Ungerer /* Restart the system call - no handlers present */
11060c22fafdSGreg Ungerer handle_restart(regs, NULL, 0);
11070c22fafdSGreg Ungerer
11080c22fafdSGreg Ungerer /* If there's no signal to deliver, we just restore the saved mask. */
110951a7b448SAl Viro restore_saved_sigmask();
11100c22fafdSGreg Ungerer }
1111a54f1655SAl Viro
do_notify_resume(struct pt_regs * regs)1112a54f1655SAl Viro void do_notify_resume(struct pt_regs *regs)
1113a54f1655SAl Viro {
1114e660653cSJens Axboe if (test_thread_flag(TIF_NOTIFY_SIGNAL) ||
1115e660653cSJens Axboe test_thread_flag(TIF_SIGPENDING))
1116a54f1655SAl Viro do_signal(regs);
1117a54f1655SAl Viro
11183c532798SJens Axboe if (test_thread_flag(TIF_NOTIFY_RESUME))
111903248addSEric W. Biederman resume_user_mode_work(regs);
1120a54f1655SAl Viro }
1121