xref: /linux/arch/microblaze/kernel/signal.c (revision 505a23a5)
12148daa9SMichal Simek /*
22148daa9SMichal Simek  * Signal handling
32148daa9SMichal Simek  *
42148daa9SMichal Simek  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
52148daa9SMichal Simek  * Copyright (C) 2008-2009 PetaLogix
62148daa9SMichal Simek  * Copyright (C) 2003,2004 John Williams <jwilliams@itee.uq.edu.au>
72148daa9SMichal Simek  * Copyright (C) 2001 NEC Corporation
82148daa9SMichal Simek  * Copyright (C) 2001 Miles Bader <miles@gnu.org>
92148daa9SMichal Simek  * Copyright (C) 1999,2000 Niibe Yutaka & Kaz Kojima
102148daa9SMichal Simek  * Copyright (C) 1991,1992 Linus Torvalds
112148daa9SMichal Simek  *
122148daa9SMichal Simek  * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
132148daa9SMichal Simek  *
1493b33bb6SJason Wang  * This file was derived from the sh version, arch/sh/kernel/signal.c
152148daa9SMichal Simek  *
162148daa9SMichal Simek  * This file is subject to the terms and conditions of the GNU General
172148daa9SMichal Simek  * Public License. See the file COPYING in the main directory of this
182148daa9SMichal Simek  * archive for more details.
192148daa9SMichal Simek  */
202148daa9SMichal Simek 
212148daa9SMichal Simek #include <linux/sched.h>
222148daa9SMichal Simek #include <linux/mm.h>
232148daa9SMichal Simek #include <linux/smp.h>
242148daa9SMichal Simek #include <linux/kernel.h>
252148daa9SMichal Simek #include <linux/signal.h>
262148daa9SMichal Simek #include <linux/errno.h>
272148daa9SMichal Simek #include <linux/wait.h>
282148daa9SMichal Simek #include <linux/ptrace.h>
292148daa9SMichal Simek #include <linux/unistd.h>
302148daa9SMichal Simek #include <linux/stddef.h>
312148daa9SMichal Simek #include <linux/personality.h>
322148daa9SMichal Simek #include <linux/percpu.h>
332148daa9SMichal Simek #include <linux/linkage.h>
3403248addSEric W. Biederman #include <linux/resume_user_mode.h>
352148daa9SMichal Simek #include <asm/entry.h>
362148daa9SMichal Simek #include <asm/ucontext.h>
372148daa9SMichal Simek #include <linux/uaccess.h>
382148daa9SMichal Simek #include <linux/syscalls.h>
392148daa9SMichal Simek #include <asm/cacheflush.h>
402148daa9SMichal Simek #include <asm/syscalls.h>
412148daa9SMichal Simek 
422148daa9SMichal Simek /*
432148daa9SMichal Simek  * Do a signal return; undo the signal stack.
442148daa9SMichal Simek  */
452148daa9SMichal Simek struct sigframe {
462148daa9SMichal Simek 	struct sigcontext sc;
472148daa9SMichal Simek 	unsigned long extramask[_NSIG_WORDS-1];
482148daa9SMichal Simek 	unsigned long tramp[2];	/* signal trampoline */
492148daa9SMichal Simek };
502148daa9SMichal Simek 
512148daa9SMichal Simek struct rt_sigframe {
522148daa9SMichal Simek 	struct siginfo info;
532148daa9SMichal Simek 	struct ucontext uc;
542148daa9SMichal Simek 	unsigned long tramp[2];	/* signal trampoline */
552148daa9SMichal Simek };
562148daa9SMichal Simek 
restore_sigcontext(struct pt_regs * regs,struct sigcontext __user * sc,int * rval_p)57353b431bSArnd Bergmann static int restore_sigcontext(struct pt_regs *regs,
58353b431bSArnd Bergmann 				struct sigcontext __user *sc, int *rval_p)
592148daa9SMichal Simek {
602148daa9SMichal Simek 	unsigned int err = 0;
612148daa9SMichal Simek 
622148daa9SMichal Simek #define COPY(x)		{err |= __get_user(regs->x, &sc->regs.x); }
632148daa9SMichal Simek 	COPY(r0);
642148daa9SMichal Simek 	COPY(r1);
652148daa9SMichal Simek 	COPY(r2);	COPY(r3);	COPY(r4);	COPY(r5);
662148daa9SMichal Simek 	COPY(r6);	COPY(r7);	COPY(r8);	COPY(r9);
672148daa9SMichal Simek 	COPY(r10);	COPY(r11);	COPY(r12);	COPY(r13);
682148daa9SMichal Simek 	COPY(r14);	COPY(r15);	COPY(r16);	COPY(r17);
692148daa9SMichal Simek 	COPY(r18);	COPY(r19);	COPY(r20);	COPY(r21);
702148daa9SMichal Simek 	COPY(r22);	COPY(r23);	COPY(r24);	COPY(r25);
712148daa9SMichal Simek 	COPY(r26);	COPY(r27);	COPY(r28);	COPY(r29);
722148daa9SMichal Simek 	COPY(r30);	COPY(r31);
732148daa9SMichal Simek 	COPY(pc);	COPY(ear);	COPY(esr);	COPY(fsr);
742148daa9SMichal Simek #undef COPY
752148daa9SMichal Simek 
762148daa9SMichal Simek 	*rval_p = regs->r3;
772148daa9SMichal Simek 
782148daa9SMichal Simek 	return err;
792148daa9SMichal Simek }
802148daa9SMichal Simek 
sys_rt_sigreturn(struct pt_regs * regs)813183e068SArnd Bergmann asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
822148daa9SMichal Simek {
83353b431bSArnd Bergmann 	struct rt_sigframe __user *frame =
846e83557cSMichal Simek 		(struct rt_sigframe __user *)(regs->r1);
852921e2bdSMichal Simek 
862148daa9SMichal Simek 	sigset_t set;
872148daa9SMichal Simek 	int rval;
882148daa9SMichal Simek 
8958e4257bSAl Viro 	/* Always make any pending restarted system calls return -EINTR */
90f56141e3SAndy Lutomirski 	current->restart_block.fn = do_no_restart_syscall;
9158e4257bSAl Viro 
9296d4f267SLinus Torvalds 	if (!access_ok(frame, sizeof(*frame)))
932148daa9SMichal Simek 		goto badframe;
942148daa9SMichal Simek 
952148daa9SMichal Simek 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
962148daa9SMichal Simek 		goto badframe;
972148daa9SMichal Simek 
9860c59751SMatt Fleming 	set_current_blocked(&set);
992148daa9SMichal Simek 
1002148daa9SMichal Simek 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))
1012148daa9SMichal Simek 		goto badframe;
1022148daa9SMichal Simek 
1034a9d32d3SAl Viro 	if (restore_altstack(&frame->uc.uc_stack))
104353b431bSArnd Bergmann 		goto badframe;
1052148daa9SMichal Simek 
1062148daa9SMichal Simek 	return rval;
1072148daa9SMichal Simek 
1082148daa9SMichal Simek badframe:
1093cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
1102148daa9SMichal Simek 	return 0;
1112148daa9SMichal Simek }
1122148daa9SMichal Simek 
1132148daa9SMichal Simek /*
1142148daa9SMichal Simek  * Set up a signal frame.
1152148daa9SMichal Simek  */
1162148daa9SMichal Simek 
1172148daa9SMichal Simek static int
setup_sigcontext(struct sigcontext __user * sc,struct pt_regs * regs,unsigned long mask)118353b431bSArnd Bergmann setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
1192148daa9SMichal Simek 		unsigned long mask)
1202148daa9SMichal Simek {
1212148daa9SMichal Simek 	int err = 0;
1222148daa9SMichal Simek 
1232148daa9SMichal Simek #define COPY(x)		{err |= __put_user(regs->x, &sc->regs.x); }
1242148daa9SMichal Simek 	COPY(r0);
1252148daa9SMichal Simek 	COPY(r1);
1262148daa9SMichal Simek 	COPY(r2);	COPY(r3);	COPY(r4);	COPY(r5);
1272148daa9SMichal Simek 	COPY(r6);	COPY(r7);	COPY(r8);	COPY(r9);
1282148daa9SMichal Simek 	COPY(r10);	COPY(r11);	COPY(r12);	COPY(r13);
1292148daa9SMichal Simek 	COPY(r14);	COPY(r15);	COPY(r16);	COPY(r17);
1302148daa9SMichal Simek 	COPY(r18);	COPY(r19);	COPY(r20);	COPY(r21);
1312148daa9SMichal Simek 	COPY(r22);	COPY(r23);	COPY(r24);	COPY(r25);
1322148daa9SMichal Simek 	COPY(r26);	COPY(r27);	COPY(r28);	COPY(r29);
1332148daa9SMichal Simek 	COPY(r30);	COPY(r31);
1342148daa9SMichal Simek 	COPY(pc);	COPY(ear);	COPY(esr);	COPY(fsr);
1352148daa9SMichal Simek #undef COPY
1362148daa9SMichal Simek 
1372148daa9SMichal Simek 	err |= __put_user(mask, &sc->oldmask);
1382148daa9SMichal Simek 
1392148daa9SMichal Simek 	return err;
1402148daa9SMichal Simek }
1412148daa9SMichal Simek 
1422148daa9SMichal Simek /*
1432148daa9SMichal Simek  * Determine which stack to use..
1442148daa9SMichal Simek  */
145353b431bSArnd Bergmann static inline void __user *
get_sigframe(struct ksignal * ksig,struct pt_regs * regs,size_t frame_size)146c001cd21SRichard Weinberger get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size)
1472148daa9SMichal Simek {
1482148daa9SMichal Simek 	/* Default to using normal stack */
149c001cd21SRichard Weinberger 	unsigned long sp = sigsp(regs->r1, ksig);
1502148daa9SMichal Simek 
151353b431bSArnd Bergmann 	return (void __user *)((sp - frame_size) & -8UL);
1522148daa9SMichal Simek }
1532148daa9SMichal Simek 
setup_rt_frame(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)1549c53c7ecSRichard Weinberger static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
1559c53c7ecSRichard Weinberger 			  struct pt_regs *regs)
1562148daa9SMichal Simek {
157353b431bSArnd Bergmann 	struct rt_sigframe __user *frame;
1589c53c7ecSRichard Weinberger 	int err = 0, sig = ksig->sig;
1592ee2ff87SMichal Simek 	unsigned long address = 0;
1602ee2ff87SMichal Simek 	pmd_t *pmdp;
1612ee2ff87SMichal Simek 	pte_t *ptep;
1622148daa9SMichal Simek 
163c001cd21SRichard Weinberger 	frame = get_sigframe(ksig, regs, sizeof(*frame));
1642148daa9SMichal Simek 
16596d4f267SLinus Torvalds 	if (!access_ok(frame, sizeof(*frame)))
1669c53c7ecSRichard Weinberger 		return -EFAULT;
1672148daa9SMichal Simek 
1689c53c7ecSRichard Weinberger 	if (ksig->ka.sa.sa_flags & SA_SIGINFO)
1699c53c7ecSRichard Weinberger 		err |= copy_siginfo_to_user(&frame->info, &ksig->info);
1702148daa9SMichal Simek 
1712148daa9SMichal Simek 	/* Create the ucontext. */
1722148daa9SMichal Simek 	err |= __put_user(0, &frame->uc.uc_flags);
1732cfedb97SMichal Simek 	err |= __put_user(NULL, &frame->uc.uc_link);
1744a9d32d3SAl Viro 	err |= __save_altstack(&frame->uc.uc_stack, regs->r1);
1752148daa9SMichal Simek 	err |= setup_sigcontext(&frame->uc.uc_mcontext,
1762148daa9SMichal Simek 			regs, set->sig[0]);
1772148daa9SMichal Simek 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
1782148daa9SMichal Simek 
1792148daa9SMichal Simek 	/* Set up to return from userspace. If provided, use a stub
1802148daa9SMichal Simek 	 already in userspace. */
1812148daa9SMichal Simek 	/* minus 8 is offset to cater for "rtsd r15,8" */
1822148daa9SMichal Simek 	/* addi r12, r0, __NR_sigreturn */
1832148daa9SMichal Simek 	err |= __put_user(0x31800000 | __NR_rt_sigreturn ,
1842148daa9SMichal Simek 			frame->tramp + 0);
1852148daa9SMichal Simek 	/* brki r14, 0x8 */
1862148daa9SMichal Simek 	err |= __put_user(0xb9cc0008, frame->tramp + 1);
1872148daa9SMichal Simek 
1882148daa9SMichal Simek 	/* Return from sighandler will jump to the tramp.
1892148daa9SMichal Simek 	 Negative 8 offset because return is rtsd r15, 8 */
1902148daa9SMichal Simek 	regs->r15 = ((unsigned long)frame->tramp)-8;
1912148daa9SMichal Simek 
1922ee2ff87SMichal Simek 	address = ((unsigned long)frame->tramp);
193e05c7b1fSMike Rapoport 	pmdp = pmd_off(current->mm, address);
1942148daa9SMichal Simek 
1952ee2ff87SMichal Simek 	preempt_disable();
1962ee2ff87SMichal Simek 	ptep = pte_offset_map(pmdp, address);
197*505a23a5SHugh Dickins 	if (ptep && pte_present(*ptep)) {
1982ee2ff87SMichal Simek 		address = (unsigned long) page_address(pte_page(*ptep));
1992ee2ff87SMichal Simek 		/* MS: I need add offset in page */
2002ee2ff87SMichal Simek 		address += ((unsigned long)frame->tramp) & ~PAGE_MASK;
2012ee2ff87SMichal Simek 		/* MS address is virtual */
202a66a6265SMichal Simek 		address = __virt_to_phys(address);
2032ee2ff87SMichal Simek 		invalidate_icache_range(address, address + 8);
2042ee2ff87SMichal Simek 		flush_dcache_range(address, address + 8);
2052ee2ff87SMichal Simek 	}
206*505a23a5SHugh Dickins 	if (ptep)
2072ee2ff87SMichal Simek 		pte_unmap(ptep);
2082ee2ff87SMichal Simek 	preempt_enable();
2092148daa9SMichal Simek 	if (err)
2109c53c7ecSRichard Weinberger 		return -EFAULT;
2112148daa9SMichal Simek 
2122148daa9SMichal Simek 	/* Set up registers for signal handler */
2136e83557cSMichal Simek 	regs->r1 = (unsigned long) frame;
2142921e2bdSMichal Simek 
2152148daa9SMichal Simek 	/* Signal handler args: */
2166140de5aSRichard Weinberger 	regs->r5 = sig; /* arg 0: signum */
2172148daa9SMichal Simek 	regs->r6 = (unsigned long) &frame->info; /* arg 1: siginfo */
2182148daa9SMichal Simek 	regs->r7 = (unsigned long) &frame->uc; /* arg2: ucontext */
2192148daa9SMichal Simek 	/* Offset to handle microblaze rtid r14, 0 */
2209c53c7ecSRichard Weinberger 	regs->pc = (unsigned long)ksig->ka.sa.sa_handler;
2212148daa9SMichal Simek 
2222148daa9SMichal Simek #ifdef DEBUG_SIG
2236bd55f0bSMichal Simek 	pr_info("SIG deliver (%s:%d): sp=%p pc=%08lx\n",
2242148daa9SMichal Simek 		current->comm, current->pid, frame, regs->pc);
2252148daa9SMichal Simek #endif
2262148daa9SMichal Simek 
227bcb8c8d0SMatt Fleming 	return 0;
2282148daa9SMichal Simek }
2292148daa9SMichal Simek 
2302148daa9SMichal Simek /* Handle restarting system calls */
2312148daa9SMichal Simek static inline void
handle_restart(struct pt_regs * regs,struct k_sigaction * ka,int has_handler)2322148daa9SMichal Simek handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
2332148daa9SMichal Simek {
2342148daa9SMichal Simek 	switch (regs->r3) {
2352148daa9SMichal Simek 	case -ERESTART_RESTARTBLOCK:
2362148daa9SMichal Simek 	case -ERESTARTNOHAND:
2372148daa9SMichal Simek 		if (!has_handler)
2382148daa9SMichal Simek 			goto do_restart;
2392148daa9SMichal Simek 		regs->r3 = -EINTR;
2402148daa9SMichal Simek 		break;
2412148daa9SMichal Simek 	case -ERESTARTSYS:
2422148daa9SMichal Simek 		if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
2432148daa9SMichal Simek 			regs->r3 = -EINTR;
2442148daa9SMichal Simek 			break;
2452148daa9SMichal Simek 	}
246df561f66SGustavo A. R. Silva 		fallthrough;
2472148daa9SMichal Simek 	case -ERESTARTNOINTR:
2482148daa9SMichal Simek do_restart:
2492148daa9SMichal Simek 		/* offset of 4 bytes to re-execute trap (brki) instruction */
2502148daa9SMichal Simek 		regs->pc -= 4;
2512148daa9SMichal Simek 		break;
2522148daa9SMichal Simek 	}
2532148daa9SMichal Simek }
2542148daa9SMichal Simek 
2552148daa9SMichal Simek /*
2562148daa9SMichal Simek  * OK, we're invoking a handler
2572148daa9SMichal Simek  */
2582148daa9SMichal Simek 
259a610d6e6SAl Viro static void
handle_signal(struct ksignal * ksig,struct pt_regs * regs)2609c53c7ecSRichard Weinberger handle_signal(struct ksignal *ksig, struct pt_regs *regs)
2612148daa9SMichal Simek {
262b7f9a11aSAl Viro 	sigset_t *oldset = sigmask_to_save();
263bcb8c8d0SMatt Fleming 	int ret;
264bcb8c8d0SMatt Fleming 
2652148daa9SMichal Simek 	/* Set up the stack frame */
2669c53c7ecSRichard Weinberger 	ret = setup_rt_frame(ksig, oldset, regs);
2672148daa9SMichal Simek 
2689c53c7ecSRichard Weinberger 	signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
2692148daa9SMichal Simek }
2702148daa9SMichal Simek 
2712148daa9SMichal Simek /*
2722148daa9SMichal Simek  * Note that 'init' is a special process: it doesn't get signals it doesn't
2732148daa9SMichal Simek  * want to handle. Thus you cannot kill init even with a SIGKILL even by
2742148daa9SMichal Simek  * mistake.
2752148daa9SMichal Simek  *
2762148daa9SMichal Simek  * Note that we go through the signals twice: once to check the signals that
2772148daa9SMichal Simek  * the kernel can handle, and then we build all the user-level signal handling
2782148daa9SMichal Simek  * stack-frames in one go after that.
2792148daa9SMichal Simek  */
do_signal(struct pt_regs * regs,int in_syscall)28083140191SAl Viro static void do_signal(struct pt_regs *regs, int in_syscall)
2812148daa9SMichal Simek {
2829c53c7ecSRichard Weinberger 	struct ksignal ksig;
2839c53c7ecSRichard Weinberger 
2842148daa9SMichal Simek #ifdef DEBUG_SIG
2856bd55f0bSMichal Simek 	pr_info("do signal: %p %d\n", regs, in_syscall);
2866bd55f0bSMichal Simek 	pr_info("do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1,
287e538c584SMark Rutland 			regs->r12, read_thread_flags());
2882148daa9SMichal Simek #endif
2892148daa9SMichal Simek 
2909c53c7ecSRichard Weinberger 	if (get_signal(&ksig)) {
2912148daa9SMichal Simek 		/* Whee! Actually deliver the signal. */
2922148daa9SMichal Simek 		if (in_syscall)
2939c53c7ecSRichard Weinberger 			handle_restart(regs, &ksig.ka, 1);
2949c53c7ecSRichard Weinberger 		handle_signal(&ksig, regs);
29583140191SAl Viro 		return;
2962148daa9SMichal Simek 	}
2972148daa9SMichal Simek 
2982148daa9SMichal Simek 	if (in_syscall)
2992148daa9SMichal Simek 		handle_restart(regs, NULL, 0);
3002148daa9SMichal Simek 
3013183e068SArnd Bergmann 	/*
3023183e068SArnd Bergmann 	 * If there's no signal to deliver, we just put the saved sigmask
3033183e068SArnd Bergmann 	 * back.
3043183e068SArnd Bergmann 	 */
30551a7b448SAl Viro 	restore_saved_sigmask();
3062148daa9SMichal Simek }
307969a9616SAl Viro 
do_notify_resume(struct pt_regs * regs,int in_syscall)3084378bb69SMichal Simek asmlinkage void do_notify_resume(struct pt_regs *regs, int in_syscall)
309969a9616SAl Viro {
310ed2124c0SJens Axboe 	if (test_thread_flag(TIF_SIGPENDING) ||
311ed2124c0SJens Axboe 	    test_thread_flag(TIF_NOTIFY_SIGNAL))
31283140191SAl Viro 		do_signal(regs, in_syscall);
313969a9616SAl Viro 
3143c532798SJens Axboe 	if (test_thread_flag(TIF_NOTIFY_RESUME))
31503248addSEric W. Biederman 		resume_user_mode_work(regs);
316969a9616SAl Viro }
317