xref: /openbsd/sys/arch/m88k/m88k/sig_machdep.c (revision b1f183b6)
1 /*	$OpenBSD: sig_machdep.c,v 1.32 2024/10/14 08:42:39 jsg 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 
79 vaddr_t	local_stack_frame(struct trapframe *, vaddr_t, size_t);
80 
81 /*
82  * WARNING: sigcode() in subr.s assumes sf_scp is the first field of the
83  * sigframe.
84  */
85 struct sigframe {
86 	struct sigcontext	*sf_scp;	/* context ptr for handler */
87 	struct sigcontext	 sf_sc;		/* actual context */
88 	siginfo_t		 sf_si;
89 };
90 
91 #ifdef DEBUG
92 int sigdebug = 0;
93 pid_t sigpid = 0;
94 #define SDB_FOLLOW	0x01
95 #define SDB_KSTACK	0x02
96 #endif
97 
98 /*
99  * Send an interrupt to process.
100  */
101 int
sendsig(sig_t catcher,int sig,sigset_t mask,const siginfo_t * ksip,int info,int onstack)102 sendsig(sig_t catcher, int sig, sigset_t mask, const siginfo_t *ksip,
103     int info, int onstack)
104 {
105 	struct proc *p = curproc;
106 	struct trapframe *tf;
107 	struct sigframe *fp;
108 	size_t fsize;
109 	struct sigframe sf;
110 	vaddr_t addr;
111 
112 	tf = p->p_md.md_tf;
113 
114 	if (info)
115 		fsize = sizeof(struct sigframe);
116 	else
117 		fsize = offsetof(struct sigframe, sf_si);
118 
119 	/*
120 	 * Allocate space for the signal handler context.
121 	 */
122 	if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 &&
123 	    !sigonstack(tf->tf_r[31]) && onstack) {
124 		addr = local_stack_frame(tf,
125 		    trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size),
126 		    fsize);
127 	} else
128 		addr = local_stack_frame(tf, tf->tf_r[31], fsize);
129 
130 	fp = (struct sigframe *)addr;
131 
132 	/*
133 	 * Build the signal context to be used by sigreturn.
134 	 */
135 	bzero(&sf, fsize);
136 	sf.sf_scp = &fp->sf_sc;
137 	sf.sf_sc.sc_mask = mask;
138 	sf.sf_sc.sc_cookie = (long)sf.sf_scp ^ p->p_p->ps_sigcookie;
139 
140 	if (info)
141 		sf.sf_si = *ksip;
142 
143 	/*
144 	 * Copy the whole user context into signal context that we
145 	 * are building.
146 	 */
147 	bcopy((const void *)&tf->tf_regs, (void *)&sf.sf_sc.sc_regs,
148 	    sizeof(sf.sf_sc.sc_regs));
149 
150 	if (copyout((caddr_t)&sf, (caddr_t)fp, fsize))
151 		return 1;
152 
153 	/*
154 	 * Set up registers for the signal handler invocation.
155 	 */
156 	tf->tf_r[1] = p->p_p->ps_sigcode;	/* return to sigcode */
157 	tf->tf_r[2] = sig;			/* first arg is signo */
158 	tf->tf_r[3] = info ? (vaddr_t)&fp->sf_si : 0;
159 	tf->tf_r[4] = (vaddr_t)&fp->sf_sc;
160 	tf->tf_r[31] = (vaddr_t)fp;
161 	addr = (vaddr_t)catcher;		/* and resume in the handler */
162 #ifdef M88100
163 	if (CPU_IS88100) {
164 		tf->tf_snip = (addr & NIP_ADDR) | NIP_V;
165 		tf->tf_sfip = (tf->tf_snip + 4) | FIP_V;
166 	}
167 #endif
168 #ifdef M88110
169 	if (CPU_IS88110)
170 		tf->tf_exip = (addr & XIP_ADDR);
171 #endif
172 
173 #ifdef DEBUG
174 	if ((sigdebug & SDB_FOLLOW) ||
175 	    ((sigdebug & SDB_KSTACK) && p->p_p->ps_pid == sigpid))
176 		printf("sendsig(%d): sig %d returns\n", p->p_p->ps_pid, sig);
177 #endif
178 
179 	return 0;
180 }
181 
182 /*
183  * System call to cleanup state after a signal has been taken.  Reset signal
184  * mask and stack state from context left by sendsig (above).  Return to
185  * previous pc and psl as specified by context left by sendsig.  Check
186  * carefully to make sure that the user has not modified the psl to gain
187  * improper privileges or to cause a machine fault.
188  */
189 int
sys_sigreturn(struct proc * p,void * v,register_t * retval)190 sys_sigreturn(struct proc *p, void *v, register_t *retval)
191 {
192 	struct sys_sigreturn_args /* {
193 	   syscallarg(struct sigcontext *) sigcntxp;
194 	} */ *uap = v;
195 	struct sigcontext ksc, *scp = SCARG(uap, sigcntxp);
196 	struct trapframe *tf;
197 	int error;
198 	vaddr_t pc;
199 
200 	tf = p->p_md.md_tf;
201 
202 	/*
203 	 * This is simpler than PROC_PC, assuming XIP is always valid
204 	 * on 88100, and doesn't have a delay slot on 88110
205 	 * (which is the status we expect from the signal code).
206 	 */
207 	pc = CPU_IS88110 ? tf->tf_regs.exip : tf->tf_regs.sxip ^ XIP_V;
208 	if (pc != p->p_p->ps_sigcoderet) {
209 		sigexit(p, SIGILL);
210 		return (EPERM);
211 	}
212 
213 	if (((vaddr_t)scp & 3) != 0)
214 		return (EFAULT);
215 
216 	if ((error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(*scp))))
217 		return (error);
218 
219 	if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) {
220 		sigexit(p, SIGILL);
221 		return (EFAULT);
222 	}
223 
224 	/* Prevent reuse of the sigcontext cookie */
225 	ksc.sc_cookie = 0;
226 	(void)copyout(&ksc.sc_cookie, (caddr_t)scp +
227 	    offsetof(struct sigcontext, sc_cookie), sizeof (ksc.sc_cookie));
228 
229 	if ((((struct reg *)&ksc.sc_regs)->epsr ^ tf->tf_regs.epsr) &
230 	    PSR_USERSTATIC)
231 		return (EINVAL);
232 
233 	bcopy((const void *)&ksc.sc_regs, (caddr_t)&tf->tf_regs,
234 	    sizeof(ksc.sc_regs));
235 
236 	/*
237 	 * Restore the user supplied information
238 	 */
239 	p->p_sigmask = ksc.sc_mask & ~sigcantmask;
240 
241 #ifdef M88100
242 	if (CPU_IS88100) {
243 		/*
244 		 * If we are returning from a signal handler triggered by
245 		 * a data access exception, the interrupted access has
246 		 * never been performed, and will not be reissued upon
247 		 * returning to userland.
248 		 *
249 		 * We can't simply call data_access_emulation(), for
250 		 * it might fault again. Instead, we invoke trap()
251 		 * again, which will either trigger another signal,
252 		 * or end up invoking data_access_emulation if safe.
253 		 */
254 		if (ISSET(tf->tf_dmt0, DMT_VALID))
255 			m88100_trap(T_DATAFLT, tf);
256 	}
257 #endif
258 
259 	/*
260 	 * We really want to return to the instruction pointed to by the
261 	 * sigcontext.  However, due to the way exceptions work on 88110,
262 	 * returning EJUSTRETURN will cause m88110_syscall() to skip one
263 	 * instruction.  We avoid this by returning ERESTART, which will
264 	 * indeed cause the instruction pointed to by exip to be run
265 	 * again.
266 	 */
267 	return CPU_IS88100 ? EJUSTRETURN : ERESTART;
268 }
269 
270 /*
271  * Find out a safe place on the process' stack to put the sigframe struct.
272  * While on 88110, this is straightforward, on 88100 we need to be
273  * careful and not stomp over potential uncompleted data accesses, which
274  * we will want to be able to perform upon sigreturn().
275  */
276 vaddr_t
local_stack_frame(struct trapframe * tf,vaddr_t tos,size_t fsize)277 local_stack_frame(struct trapframe *tf, vaddr_t tos, size_t fsize)
278 {
279 	vaddr_t frame;
280 
281 	frame = (tos - fsize) & ~_STACKALIGNBYTES;
282 
283 #ifdef M88100
284 	if (CPU_IS88100 && ISSET(tf->tf_dmt0, DMT_VALID)) {
285 		for (;;) {
286 			tos = frame + fsize;
287 			if (/* ISSET(tf->tf_dmt0, DMT_VALID) && */
288 			    tf->tf_dma0 >= frame && tf->tf_dma0 < tos) {
289 				frame = (tf->tf_dma0 - fsize) &
290 				    ~_STACKALIGNBYTES;
291 				continue;
292 			}
293 			if (ISSET(tf->tf_dmt1, DMT_VALID) &&
294 			    tf->tf_dma1 >= frame && tf->tf_dma1 < tos) {
295 				frame = (tf->tf_dma1 - fsize) &
296 				    ~_STACKALIGNBYTES;
297 				continue;
298 			}
299 			if (ISSET(tf->tf_dmt2, DMT_VALID) &&
300 			    tf->tf_dma2 >= frame && tf->tf_dma2 < tos) {
301 				frame = (tf->tf_dma2 - fsize) &
302 				    ~_STACKALIGNBYTES;
303 				continue;
304 			}
305 			break;
306 		}
307 	}
308 #endif
309 
310 	return frame;
311 }
312