xref: /openbmc/linux/arch/m68k/kernel/signal.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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