xref: /openbmc/linux/arch/openrisc/kernel/signal.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ac689eb7SJonas Bonn /*
3ac689eb7SJonas Bonn  * OpenRISC signal.c
4ac689eb7SJonas Bonn  *
5ac689eb7SJonas Bonn  * Linux architectural port borrowing liberally from similar works of
6ac689eb7SJonas Bonn  * others.  All original copyrights apply as per the original source
7ac689eb7SJonas Bonn  * declaration.
8ac689eb7SJonas Bonn  *
9ac689eb7SJonas Bonn  * Modifications for the OpenRISC architecture:
10ac689eb7SJonas Bonn  * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
11ac689eb7SJonas Bonn  * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
12ac689eb7SJonas Bonn  */
13ac689eb7SJonas Bonn 
14ac689eb7SJonas Bonn #include <linux/sched.h>
15ac689eb7SJonas Bonn #include <linux/mm.h>
16ac689eb7SJonas Bonn #include <linux/smp.h>
17ac689eb7SJonas Bonn #include <linux/kernel.h>
18ac689eb7SJonas Bonn #include <linux/signal.h>
19ac689eb7SJonas Bonn #include <linux/errno.h>
20ac689eb7SJonas Bonn #include <linux/wait.h>
21ac689eb7SJonas Bonn #include <linux/ptrace.h>
22ac689eb7SJonas Bonn #include <linux/unistd.h>
23ac689eb7SJonas Bonn #include <linux/stddef.h>
2403248addSEric W. Biederman #include <linux/resume_user_mode.h>
25ac689eb7SJonas Bonn 
26ac689eb7SJonas Bonn #include <asm/processor.h>
2710f67dbfSJonas Bonn #include <asm/syscall.h>
28ac689eb7SJonas Bonn #include <asm/ucontext.h>
297c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
30ac689eb7SJonas Bonn 
31ac689eb7SJonas Bonn struct rt_sigframe {
32ac689eb7SJonas Bonn 	struct siginfo info;
33ac689eb7SJonas Bonn 	struct ucontext uc;
34ac689eb7SJonas Bonn 	unsigned char retcode[16];	/* trampoline code */
35ac689eb7SJonas Bonn };
36ac689eb7SJonas Bonn 
371c4de499SStafford Horne asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs);
381c4de499SStafford Horne 
391c4de499SStafford Horne asmlinkage int do_work_pending(struct pt_regs *regs, unsigned int thread_flags,
401c4de499SStafford Horne 			       int syscall);
411c4de499SStafford Horne 
restore_sigcontext(struct pt_regs * regs,struct sigcontext __user * sc)4210f67dbfSJonas Bonn static int restore_sigcontext(struct pt_regs *regs,
4310f67dbfSJonas Bonn 			      struct sigcontext __user *sc)
44ac689eb7SJonas Bonn {
4510f67dbfSJonas Bonn 	int err = 0;
46ac689eb7SJonas Bonn 
4710f67dbfSJonas Bonn 	/* Always make any pending restarted system calls return -EINTR */
48f56141e3SAndy Lutomirski 	current->restart_block.fn = do_no_restart_syscall;
49ac689eb7SJonas Bonn 
50d7cb6667SJonas Bonn 	/*
51d7cb6667SJonas Bonn 	 * Restore the regs from &sc->regs.
5296d4f267SLinus Torvalds 	 * (sc is already checked since the sigframe was
53ac689eb7SJonas Bonn 	 *  checked in sys_sigreturn previously)
54ac689eb7SJonas Bonn 	 */
5510f67dbfSJonas Bonn 	err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long));
5610f67dbfSJonas Bonn 	err |= __copy_from_user(&regs->pc, &sc->regs.pc, sizeof(unsigned long));
5710f67dbfSJonas Bonn 	err |= __copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long));
58dceaafd6SStafford Horne 	err |= __copy_from_user(&regs->fpcsr, &sc->fpcsr, sizeof(unsigned long));
59ac689eb7SJonas Bonn 
60ac689eb7SJonas Bonn 	/* make sure the SM-bit is cleared so user-mode cannot fool us */
61ac689eb7SJonas Bonn 	regs->sr &= ~SPR_SR_SM;
62ac689eb7SJonas Bonn 
6310f67dbfSJonas Bonn 	regs->orig_gpr11 = -1;	/* Avoid syscall restart checks */
6410f67dbfSJonas Bonn 
65ac689eb7SJonas Bonn 	/* TODO: the other ports use regs->orig_XX to disable syscall checks
66ac689eb7SJonas Bonn 	 * after this completes, but we don't use that mechanism. maybe we can
67ac689eb7SJonas Bonn 	 * use it now ?
68ac689eb7SJonas Bonn 	 */
69ac689eb7SJonas Bonn 
70ac689eb7SJonas Bonn 	return err;
71ac689eb7SJonas Bonn }
72ac689eb7SJonas Bonn 
_sys_rt_sigreturn(struct pt_regs * regs)73ac689eb7SJonas Bonn asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs)
74ac689eb7SJonas Bonn {
75d9959664SStafford Horne 	struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->sp;
76ac689eb7SJonas Bonn 	sigset_t set;
77ac689eb7SJonas Bonn 
78ac689eb7SJonas Bonn 	/*
79ac689eb7SJonas Bonn 	 * Since we stacked the signal on a dword boundary,
80ac689eb7SJonas Bonn 	 * then frame should be dword aligned here.  If it's
81ac689eb7SJonas Bonn 	 * not, then the user is trying to mess with us.
82ac689eb7SJonas Bonn 	 */
83d9959664SStafford Horne 	if (((unsigned long)frame) & 3)
84ac689eb7SJonas Bonn 		goto badframe;
85ac689eb7SJonas Bonn 
8696d4f267SLinus Torvalds 	if (!access_ok(frame, sizeof(*frame)))
87ac689eb7SJonas Bonn 		goto badframe;
88ac689eb7SJonas Bonn 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
89ac689eb7SJonas Bonn 		goto badframe;
90ac689eb7SJonas Bonn 
91d8d4b20dSMatt Fleming 	set_current_blocked(&set);
92ac689eb7SJonas Bonn 
93ac689eb7SJonas Bonn 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
94ac689eb7SJonas Bonn 		goto badframe;
95ac689eb7SJonas Bonn 
96faec5a96SAl Viro 	if (restore_altstack(&frame->uc.uc_stack))
97d26654e5SAl Viro 		goto badframe;
98ac689eb7SJonas Bonn 
99ac689eb7SJonas Bonn 	return regs->gpr[11];
100ac689eb7SJonas Bonn 
101ac689eb7SJonas Bonn badframe:
1023cf5d076SEric W. Biederman 	force_sig(SIGSEGV);
103ac689eb7SJonas Bonn 	return 0;
104ac689eb7SJonas Bonn }
105ac689eb7SJonas Bonn 
106ac689eb7SJonas Bonn /*
107ac689eb7SJonas Bonn  * Set up a signal frame.
108ac689eb7SJonas Bonn  */
109ac689eb7SJonas Bonn 
setup_sigcontext(struct pt_regs * regs,struct sigcontext __user * sc)11010f67dbfSJonas Bonn static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
111ac689eb7SJonas Bonn {
112ac689eb7SJonas Bonn 	int err = 0;
113ac689eb7SJonas Bonn 
114d7cb6667SJonas Bonn 	/* copy the regs */
11510f67dbfSJonas Bonn 	/* There should be no need to save callee-saved registers here...
11610f67dbfSJonas Bonn 	 * ...but we save them anyway.  Revisit this
11710f67dbfSJonas Bonn 	 */
118d7cb6667SJonas Bonn 	err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long));
119d7cb6667SJonas Bonn 	err |= __copy_to_user(&sc->regs.pc, &regs->pc, sizeof(unsigned long));
120d7cb6667SJonas Bonn 	err |= __copy_to_user(&sc->regs.sr, &regs->sr, sizeof(unsigned long));
121dceaafd6SStafford Horne 	err |= __copy_to_user(&sc->fpcsr, &regs->fpcsr, sizeof(unsigned long));
122ac689eb7SJonas Bonn 
123ac689eb7SJonas Bonn 	return err;
124ac689eb7SJonas Bonn }
125ac689eb7SJonas Bonn 
align_sigframe(unsigned long sp)126ac689eb7SJonas Bonn static inline unsigned long align_sigframe(unsigned long sp)
127ac689eb7SJonas Bonn {
128ac689eb7SJonas Bonn 	return sp & ~3UL;
129ac689eb7SJonas Bonn }
130ac689eb7SJonas Bonn 
131ac689eb7SJonas Bonn /*
132ac689eb7SJonas Bonn  * Work out where the signal frame should go.  It's either on the user stack
133ac689eb7SJonas Bonn  * or the alternate stack.
134ac689eb7SJonas Bonn  */
135ac689eb7SJonas Bonn 
get_sigframe(struct ksignal * ksig,struct pt_regs * regs,size_t frame_size)1368e2beafaSRichard Weinberger static inline void __user *get_sigframe(struct ksignal *ksig,
137ac689eb7SJonas Bonn 					struct pt_regs *regs, size_t frame_size)
138ac689eb7SJonas Bonn {
139ac689eb7SJonas Bonn 	unsigned long sp = regs->sp;
140ac689eb7SJonas Bonn 
141ac689eb7SJonas Bonn 	/* redzone */
142ac689eb7SJonas Bonn 	sp -= STACK_FRAME_OVERHEAD;
1438e2beafaSRichard Weinberger 	sp = sigsp(sp, ksig);
144ac689eb7SJonas Bonn 	sp = align_sigframe(sp - frame_size);
145ac689eb7SJonas Bonn 
146ac689eb7SJonas Bonn 	return (void __user *)sp;
147ac689eb7SJonas Bonn }
148ac689eb7SJonas Bonn 
149ac689eb7SJonas Bonn /* grab and setup a signal frame.
150ac689eb7SJonas Bonn  *
151ac689eb7SJonas Bonn  * basically we stack a lot of state info, and arrange for the
152ac689eb7SJonas Bonn  * user-mode program to return to the kernel using either a
153ac689eb7SJonas Bonn  * trampoline which performs the syscall sigreturn, or a provided
154ac689eb7SJonas Bonn  * user-mode trampoline.
155ac689eb7SJonas Bonn  */
setup_rt_frame(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)156548dafe8SRichard Weinberger static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
157548dafe8SRichard Weinberger 			  struct pt_regs *regs)
158ac689eb7SJonas Bonn {
159d9959664SStafford Horne 	struct rt_sigframe __user *frame;
160ac689eb7SJonas Bonn 	unsigned long return_ip;
161ac689eb7SJonas Bonn 	int err = 0;
162ac689eb7SJonas Bonn 
1638e2beafaSRichard Weinberger 	frame = get_sigframe(ksig, regs, sizeof(*frame));
164548dafe8SRichard Weinberger 
16596d4f267SLinus Torvalds 	if (!access_ok(frame, sizeof(*frame)))
166548dafe8SRichard Weinberger 		return -EFAULT;
167ac689eb7SJonas Bonn 
16810f67dbfSJonas Bonn 	/* Create siginfo.  */
169548dafe8SRichard Weinberger 	if (ksig->ka.sa.sa_flags & SA_SIGINFO)
170548dafe8SRichard Weinberger 		err |= copy_siginfo_to_user(&frame->info, &ksig->info);
171ac689eb7SJonas Bonn 
17210f67dbfSJonas Bonn 	/* Create the ucontext.  */
173ac689eb7SJonas Bonn 	err |= __put_user(0, &frame->uc.uc_flags);
174ac689eb7SJonas Bonn 	err |= __put_user(NULL, &frame->uc.uc_link);
175faec5a96SAl Viro 	err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
17610f67dbfSJonas Bonn 	err |= setup_sigcontext(regs, &frame->uc.uc_mcontext);
177ac689eb7SJonas Bonn 
178ac689eb7SJonas Bonn 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
179ac689eb7SJonas Bonn 
180ac689eb7SJonas Bonn 	if (err)
181548dafe8SRichard Weinberger 		return -EFAULT;
182ac689eb7SJonas Bonn 
183ac689eb7SJonas Bonn 	/* trampoline - the desired return ip is the retcode itself */
184ac689eb7SJonas Bonn 	return_ip = (unsigned long)&frame->retcode;
18510f67dbfSJonas Bonn 	/* This is:
18610f67dbfSJonas Bonn 		l.ori r11,r0,__NR_sigreturn
18710f67dbfSJonas Bonn 		l.sys 1
18810f67dbfSJonas Bonn 	 */
189d9959664SStafford Horne 	err |= __put_user(0xa960,             (short __user *)(frame->retcode + 0));
190d9959664SStafford Horne 	err |= __put_user(__NR_rt_sigreturn,  (short __user *)(frame->retcode + 2));
191d9959664SStafford Horne 	err |= __put_user(0x20000001, (unsigned long __user *)(frame->retcode + 4));
192d9959664SStafford Horne 	err |= __put_user(0x15000000, (unsigned long __user *)(frame->retcode + 8));
193ac689eb7SJonas Bonn 
194ac689eb7SJonas Bonn 	if (err)
195548dafe8SRichard Weinberger 		return -EFAULT;
196ac689eb7SJonas Bonn 
197ac689eb7SJonas Bonn 	/* Set up registers for signal handler */
198548dafe8SRichard Weinberger 	regs->pc = (unsigned long)ksig->ka.sa.sa_handler; /* what we enter NOW */
199ac689eb7SJonas Bonn 	regs->gpr[9] = (unsigned long)return_ip;     /* what we enter LATER */
200548dafe8SRichard Weinberger 	regs->gpr[3] = (unsigned long)ksig->sig;           /* arg 1: signo */
201ac689eb7SJonas Bonn 	regs->gpr[4] = (unsigned long)&frame->info;  /* arg 2: (siginfo_t*) */
202ac689eb7SJonas Bonn 	regs->gpr[5] = (unsigned long)&frame->uc;    /* arg 3: ucontext */
203ac689eb7SJonas Bonn 
204ac689eb7SJonas Bonn 	/* actually move the usp to reflect the stacked frame */
205ac689eb7SJonas Bonn 	regs->sp = (unsigned long)frame;
206ac689eb7SJonas Bonn 
207e933c70dSMatt Fleming 	return 0;
208ac689eb7SJonas Bonn }
209ac689eb7SJonas Bonn 
21039974d08SAl Viro static inline void
handle_signal(struct ksignal * ksig,struct pt_regs * regs)211548dafe8SRichard Weinberger handle_signal(struct ksignal *ksig, struct pt_regs *regs)
212ac689eb7SJonas Bonn {
213e933c70dSMatt Fleming 	int ret;
214e933c70dSMatt Fleming 
215548dafe8SRichard Weinberger 	ret = setup_rt_frame(ksig, sigmask_to_save(), regs);
216ac689eb7SJonas Bonn 
217548dafe8SRichard Weinberger 	signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
218ac689eb7SJonas Bonn }
219ac689eb7SJonas Bonn 
220ac689eb7SJonas Bonn /*
221ac689eb7SJonas Bonn  * Note that 'init' is a special process: it doesn't get signals it doesn't
222ac689eb7SJonas Bonn  * want to handle. Thus you cannot kill init even with a SIGKILL even by
223ac689eb7SJonas Bonn  * mistake.
224ac689eb7SJonas Bonn  *
225ac689eb7SJonas Bonn  * Also note that the regs structure given here as an argument, is the latest
226ac689eb7SJonas Bonn  * pushed pt_regs. It may or may not be the same as the first pushed registers
227ac689eb7SJonas Bonn  * when the initial usermode->kernelmode transition took place. Therefore
228ac689eb7SJonas Bonn  * we can use user_mode(regs) to see if we came directly from kernel or user
229ac689eb7SJonas Bonn  * mode below.
230ac689eb7SJonas Bonn  */
231ac689eb7SJonas Bonn 
do_signal(struct pt_regs * regs,int syscall)232*af1fc740SStafford Horne static int do_signal(struct pt_regs *regs, int syscall)
233ac689eb7SJonas Bonn {
234548dafe8SRichard Weinberger 	struct ksignal ksig;
23510f67dbfSJonas Bonn 	unsigned long continue_addr = 0;
23610f67dbfSJonas Bonn 	unsigned long restart_addr = 0;
23710f67dbfSJonas Bonn 	unsigned long retval = 0;
238ac689eb7SJonas Bonn 	int restart = 0;
239ac689eb7SJonas Bonn 
24010f67dbfSJonas Bonn 	if (syscall) {
24110f67dbfSJonas Bonn 		continue_addr = regs->pc;
24210f67dbfSJonas Bonn 		restart_addr = continue_addr - 4;
24310f67dbfSJonas Bonn 		retval = regs->gpr[11];
24410f67dbfSJonas Bonn 
24510f67dbfSJonas Bonn 		/*
24610f67dbfSJonas Bonn 		 * Setup syscall restart here so that a debugger will
24710f67dbfSJonas Bonn 		 * see the already changed PC.
24810f67dbfSJonas Bonn 		 */
24910f67dbfSJonas Bonn 		switch (retval) {
250ac689eb7SJonas Bonn 		case -ERESTART_RESTARTBLOCK:
25110f67dbfSJonas Bonn 			restart = -2;
252df561f66SGustavo A. R. Silva 			fallthrough;
253ac689eb7SJonas Bonn 		case -ERESTARTNOHAND:
254ac689eb7SJonas Bonn 		case -ERESTARTSYS:
255ac689eb7SJonas Bonn 		case -ERESTARTNOINTR:
25610f67dbfSJonas Bonn 			restart++;
25710f67dbfSJonas Bonn 			regs->gpr[11] = regs->orig_gpr11;
25810f67dbfSJonas Bonn 			regs->pc = restart_addr;
259ac689eb7SJonas Bonn 			break;
260ac689eb7SJonas Bonn 		}
26110f67dbfSJonas Bonn 	}
262ac689eb7SJonas Bonn 
26310f67dbfSJonas Bonn 	/*
264548dafe8SRichard Weinberger 	 * Get the signal to deliver.  During the call to get_signal the
265548dafe8SRichard Weinberger 	 * debugger may change all our registers so we may need to revert
266548dafe8SRichard Weinberger 	 * the decision to restart the syscall; specifically, if the PC is
267548dafe8SRichard Weinberger 	 * changed, don't restart the syscall.
26810f67dbfSJonas Bonn 	 */
269548dafe8SRichard Weinberger 	if (get_signal(&ksig)) {
27010f67dbfSJonas Bonn 		if (unlikely(restart) && regs->pc == restart_addr) {
27110f67dbfSJonas Bonn 			if (retval == -ERESTARTNOHAND ||
27210f67dbfSJonas Bonn 			    retval == -ERESTART_RESTARTBLOCK
27310f67dbfSJonas Bonn 			    || (retval == -ERESTARTSYS
274548dafe8SRichard Weinberger 			        && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
27510f67dbfSJonas Bonn 				/* No automatic restart */
276ac689eb7SJonas Bonn 				regs->gpr[11] = -EINTR;
27710f67dbfSJonas Bonn 				regs->pc = continue_addr;
278ac689eb7SJonas Bonn 			}
279ac689eb7SJonas Bonn 		}
280548dafe8SRichard Weinberger 		handle_signal(&ksig, regs);
28110f67dbfSJonas Bonn 	} else {
28210f67dbfSJonas Bonn 		/* no handler */
28310f67dbfSJonas Bonn 		restore_saved_sigmask();
28410f67dbfSJonas Bonn 		/*
28510f67dbfSJonas Bonn 		 * Restore pt_regs PC as syscall restart will be handled by
28610f67dbfSJonas Bonn 		 * kernel without return to userspace
28710f67dbfSJonas Bonn 		 */
28810f67dbfSJonas Bonn 		if (unlikely(restart) && regs->pc == restart_addr) {
28910f67dbfSJonas Bonn 			regs->pc = continue_addr;
29010f67dbfSJonas Bonn 			return restart;
29110f67dbfSJonas Bonn 		}
292ac689eb7SJonas Bonn 	}
293ac689eb7SJonas Bonn 
29410f67dbfSJonas Bonn 	return 0;
295ac689eb7SJonas Bonn }
296ac689eb7SJonas Bonn 
29710f67dbfSJonas Bonn asmlinkage int
do_work_pending(struct pt_regs * regs,unsigned int thread_flags,int syscall)29810f67dbfSJonas Bonn do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
299ac689eb7SJonas Bonn {
30010f67dbfSJonas Bonn 	do {
30110f67dbfSJonas Bonn 		if (likely(thread_flags & _TIF_NEED_RESCHED)) {
30210f67dbfSJonas Bonn 			schedule();
30310f67dbfSJonas Bonn 		} else {
30410f67dbfSJonas Bonn 			if (unlikely(!user_mode(regs)))
30510f67dbfSJonas Bonn 				return 0;
30610f67dbfSJonas Bonn 			local_irq_enable();
307e181c0aaSJens Axboe 			if (thread_flags & (_TIF_SIGPENDING|_TIF_NOTIFY_SIGNAL)) {
30810f67dbfSJonas Bonn 				int restart = do_signal(regs, syscall);
30910f67dbfSJonas Bonn 				if (unlikely(restart)) {
31010f67dbfSJonas Bonn 					/*
31110f67dbfSJonas Bonn 					 * Restart without handlers.
31210f67dbfSJonas Bonn 					 * Deal with it without leaving
31310f67dbfSJonas Bonn 					 * the kernel space.
31410f67dbfSJonas Bonn 					 */
31510f67dbfSJonas Bonn 					return restart;
31610f67dbfSJonas Bonn 				}
31710f67dbfSJonas Bonn 				syscall = 0;
31810f67dbfSJonas Bonn 			} else {
31903248addSEric W. Biederman 				resume_user_mode_work(regs);
320ac689eb7SJonas Bonn 			}
321ac689eb7SJonas Bonn 		}
32210f67dbfSJonas Bonn 		local_irq_disable();
3234ea7ce0aSMark Rutland 		thread_flags = read_thread_flags();
32410f67dbfSJonas Bonn 	} while (thread_flags & _TIF_WORK_MASK);
32510f67dbfSJonas Bonn 	return 0;
32610f67dbfSJonas Bonn }
327