1/*	$OpenBSD: sig_machdep.c,v 1.31 2021/10/06 15:46:03 claudio Exp $	*/
2/*
3 * Copyright (c) 2014 Miodrag Vallat.
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17/*
18 * Copyright (c) 1998, 1999, 2000, 2001 Steve Murphree, Jr.
19 * Copyright (c) 1996 Nivas Madhur
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 *    notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 *    notice, this list of conditions and the following disclaimer in the
29 *    documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 *    must display the following acknowledgement:
32 *      This product includes software developed by Nivas Madhur.
33 * 4. The name of the author may not be used to endorse or promote products
34 *    derived from this software without specific prior written permission
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
37 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
39 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
40 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
45 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 *
47 */
48/*
49 * Mach Operating System
50 * Copyright (c) 1993-1991 Carnegie Mellon University
51 * Copyright (c) 1991 OMRON Corporation
52 * All Rights Reserved.
53 *
54 * Permission to use, copy, modify and distribute this software and its
55 * documentation is hereby granted, provided that both the copyright
56 * notice and this permission notice appear in all copies of the
57 * software, derivative works or modified versions, and any portions
58 * thereof, and that both notices appear in supporting documentation.
59 *
60 */
61
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/signalvar.h>
65#include <sys/kernel.h>
66#include <sys/proc.h>
67#include <sys/mount.h>
68#include <sys/syscallargs.h>
69#include <sys/errno.h>
70
71#include <machine/reg.h>
72#ifdef M88100
73#include <machine/m88100.h>
74#include <machine/trap.h>
75#endif
76
77#include <uvm/uvm_extern.h>
78
79vaddr_t	local_stack_frame(struct trapframe *, vaddr_t, size_t);
80
81struct sigstate {
82	int		 ss_flags;	/* which of the following are valid */
83	struct trapframe ss_frame;	/* original exception frame */
84};
85
86/*
87 * WARNING: sigcode() in subr.s assumes sf_scp is the first field of the
88 * sigframe.
89 */
90struct sigframe {
91	struct sigcontext	*sf_scp;	/* context ptr for handler */
92	struct sigcontext	 sf_sc;		/* actual context */
93	siginfo_t		 sf_si;
94};
95
96#ifdef DEBUG
97int sigdebug = 0;
98pid_t sigpid = 0;
99#define SDB_FOLLOW	0x01
100#define SDB_KSTACK	0x02
101#endif
102
103/*
104 * Send an interrupt to process.
105 */
106int
107sendsig(sig_t catcher, int sig, sigset_t mask, const siginfo_t *ksip,
108    int info, int onstack)
109{
110	struct proc *p = curproc;
111	struct trapframe *tf;
112	struct sigframe *fp;
113	size_t fsize;
114	struct sigframe sf;
115	vaddr_t addr;
116
117	tf = p->p_md.md_tf;
118
119	if (info)
120		fsize = sizeof(struct sigframe);
121	else
122		fsize = offsetof(struct sigframe, sf_si);
123
124	/*
125	 * Allocate space for the signal handler context.
126	 */
127	if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 &&
128	    !sigonstack(tf->tf_r[31]) && onstack) {
129		addr = local_stack_frame(tf,
130		    trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size),
131		    fsize);
132	} else
133		addr = local_stack_frame(tf, tf->tf_r[31], fsize);
134
135	fp = (struct sigframe *)addr;
136
137	/*
138	 * Build the signal context to be used by sigreturn.
139	 */
140	bzero(&sf, fsize);
141	sf.sf_scp = &fp->sf_sc;
142	sf.sf_sc.sc_mask = mask;
143	sf.sf_sc.sc_cookie = (long)sf.sf_scp ^ p->p_p->ps_sigcookie;
144
145	if (info)
146		sf.sf_si = *ksip;
147
148	/*
149	 * Copy the whole user context into signal context that we
150	 * are building.
151	 */
152	bcopy((const void *)&tf->tf_regs, (void *)&sf.sf_sc.sc_regs,
153	    sizeof(sf.sf_sc.sc_regs));
154
155	if (copyout((caddr_t)&sf, (caddr_t)fp, fsize))
156		return 1;
157
158	/*
159	 * Set up registers for the signal handler invocation.
160	 */
161	tf->tf_r[1] = p->p_p->ps_sigcode;	/* return to sigcode */
162	tf->tf_r[2] = sig;			/* first arg is signo */
163	tf->tf_r[3] = info ? (vaddr_t)&fp->sf_si : 0;
164	tf->tf_r[4] = (vaddr_t)&fp->sf_sc;
165	tf->tf_r[31] = (vaddr_t)fp;
166	addr = (vaddr_t)catcher;		/* and resume in the handler */
167#ifdef M88100
168	if (CPU_IS88100) {
169		tf->tf_snip = (addr & NIP_ADDR) | NIP_V;
170		tf->tf_sfip = (tf->tf_snip + 4) | FIP_V;
171	}
172#endif
173#ifdef M88110
174	if (CPU_IS88110)
175		tf->tf_exip = (addr & XIP_ADDR);
176#endif
177
178#ifdef DEBUG
179	if ((sigdebug & SDB_FOLLOW) ||
180	    ((sigdebug & SDB_KSTACK) && p->p_p->ps_pid == sigpid))
181		printf("sendsig(%d): sig %d returns\n", p->p_p->ps_pid, sig);
182#endif
183
184	return 0;
185}
186
187/*
188 * System call to cleanup state after a signal has been taken.  Reset signal
189 * mask and stack state from context left by sendsig (above).  Return to
190 * previous pc and psl as specified by context left by sendsig.  Check
191 * carefully to make sure that the user has not modified the psl to gain
192 * improper privileges or to cause a machine fault.
193 */
194int
195sys_sigreturn(struct proc *p, void *v, register_t *retval)
196{
197	struct sys_sigreturn_args /* {
198	   syscallarg(struct sigcontext *) sigcntxp;
199	} */ *uap = v;
200	struct sigcontext ksc, *scp = SCARG(uap, sigcntxp);
201	struct trapframe *tf;
202	int error;
203	vaddr_t pc;
204
205	tf = p->p_md.md_tf;
206
207	/*
208	 * This is simpler than PROC_PC, assuming XIP is always valid
209	 * on 88100, and doesn't have a delay slot on 88110
210	 * (which is the status we expect from the signal code).
211	 */
212	pc = CPU_IS88110 ? tf->tf_regs.exip : tf->tf_regs.sxip ^ XIP_V;
213	if (pc != p->p_p->ps_sigcoderet) {
214		sigexit(p, SIGILL);
215		return (EPERM);
216	}
217
218	if (((vaddr_t)scp & 3) != 0)
219		return (EFAULT);
220
221	if ((error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(*scp))))
222		return (error);
223
224	if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) {
225		sigexit(p, SIGILL);
226		return (EFAULT);
227	}
228
229	/* Prevent reuse of the sigcontext cookie */
230	ksc.sc_cookie = 0;
231	(void)copyout(&ksc.sc_cookie, (caddr_t)scp +
232	    offsetof(struct sigcontext, sc_cookie), sizeof (ksc.sc_cookie));
233
234	if ((((struct reg *)&ksc.sc_regs)->epsr ^ tf->tf_regs.epsr) &
235	    PSR_USERSTATIC)
236		return (EINVAL);
237
238	bcopy((const void *)&ksc.sc_regs, (caddr_t)&tf->tf_regs,
239	    sizeof(ksc.sc_regs));
240
241	/*
242	 * Restore the user supplied information
243	 */
244	p->p_sigmask = ksc.sc_mask & ~sigcantmask;
245
246#ifdef M88100
247	if (CPU_IS88100) {
248		/*
249		 * If we are returning from a signal handler triggered by
250		 * a data access exception, the interrupted access has
251		 * never been performed, and will not be reissued upon
252		 * returning to userland.
253		 *
254		 * We can't simply call data_access_emulation(), for
255		 * it might fault again. Instead, we invoke trap()
256		 * again, which will either trigger another signal,
257		 * or end up invoking data_access_emulation if safe.
258		 */
259		if (ISSET(tf->tf_dmt0, DMT_VALID))
260			m88100_trap(T_DATAFLT, tf);
261	}
262#endif
263
264	/*
265	 * We really want to return to the instruction pointed to by the
266	 * sigcontext.  However, due to the way exceptions work on 88110,
267	 * returning EJUSTRETURN will cause m88110_syscall() to skip one
268	 * instruction.  We avoid this by returning ERESTART, which will
269	 * indeed cause the instruction pointed to by exip to be run
270	 * again.
271	 */
272	return CPU_IS88100 ? EJUSTRETURN : ERESTART;
273}
274
275/*
276 * Find out a safe place on the process' stack to put the sigframe struct.
277 * While on 88110, this is straightforward, on 88100 we need to be
278 * careful and not stomp over potential uncompleted data accesses, which
279 * we will want to be able to perform upon sigreturn().
280 */
281vaddr_t
282local_stack_frame(struct trapframe *tf, vaddr_t tos, size_t fsize)
283{
284	vaddr_t frame;
285
286	frame = (tos - fsize) & ~_STACKALIGNBYTES;
287
288#ifdef M88100
289	if (CPU_IS88100 && ISSET(tf->tf_dmt0, DMT_VALID)) {
290		for (;;) {
291			tos = frame + fsize;
292			if (/* ISSET(tf->tf_dmt0, DMT_VALID) && */
293			    tf->tf_dma0 >= frame && tf->tf_dma0 < tos) {
294				frame = (tf->tf_dma0 - fsize) &
295				    ~_STACKALIGNBYTES;
296				continue;
297			}
298			if (ISSET(tf->tf_dmt1, DMT_VALID) &&
299			    tf->tf_dma1 >= frame && tf->tf_dma1 < tos) {
300				frame = (tf->tf_dma1 - fsize) &
301				    ~_STACKALIGNBYTES;
302				continue;
303			}
304			if (ISSET(tf->tf_dmt2, DMT_VALID) &&
305			    tf->tf_dma2 >= frame && tf->tf_dma2 < tos) {
306				frame = (tf->tf_dma2 - fsize) &
307				    ~_STACKALIGNBYTES;
308				continue;
309			}
310			break;
311		}
312	}
313#endif
314
315	return frame;
316}
317