1/*	$OpenBSD: sig_machdep.c,v 1.10 2022/03/22 06:49:25 miod Exp $	*/
2
3/*
4 * Copyright (c) 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * William Jolitz and Don Ahn.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *      This product includes software developed by the University of
21 *      California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 */
39/*
40 * Copyright (c) 2001 Opsycon AB  (www.opsycon.se)
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 *    notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 *    notice, this list of conditions and the following disclaimer in the
49 *    documentation and/or other materials provided with the distribution.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
52 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
53 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
55 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 */
64
65#include <sys/param.h>
66
67#include <sys/mount.h>		/* XXX only needed by syscallargs.h */
68#include <sys/proc.h>
69#include <sys/signal.h>
70#include <sys/signalvar.h>
71#include <sys/syscallargs.h>
72#include <sys/systm.h>
73#include <sys/user.h>
74
75#include <machine/cpu.h>
76#include <machine/frame.h>
77#include <machine/pcb.h>
78
79#include <uvm/uvm_extern.h>
80
81static __inline struct trapframe *
82process_frame(struct proc *p)
83{
84	return p->p_addr->u_pcb.pcb_tf;
85}
86
87/*
88 * Send an interrupt to process.
89 *
90 * Stack is set up to allow sigcode to call routine, followed by
91 * syscall to sigreturn routine below.  After sigreturn resets the
92 * signal mask, the stack, and the frame pointer, it returns to the
93 * user specified pc.
94 */
95int
96sendsig(sig_t catcher, int sig, sigset_t mask, const siginfo_t *ksip,
97    int info, int onstack)
98{
99	struct proc *p = curproc;
100	struct trapframe *tf;
101	struct sigframe *fp, frame;
102	struct fpreg *fpreg;
103	siginfo_t *sip = NULL;
104	int i;
105
106	tf = process_frame(p);
107
108	/* Allocate space for the signal handler context. */
109	if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 &&
110	    !sigonstack(tf->tf_sp) && onstack)
111		fp = (struct sigframe *)
112		    trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size);
113	else
114		fp = (struct sigframe *)tf->tf_sp;
115
116	/* make room on the stack */
117	fp--;
118
119	/* make the stack aligned */
120	fp = (struct sigframe *)STACKALIGN(fp);
121
122	/* Save FPU state to PCB if necessary. */
123	if (p->p_addr->u_pcb.pcb_flags & PCB_FPU)
124		fpu_save(p, tf);
125
126	/* Build stack frame for signal trampoline. */
127	bzero(&frame, sizeof(frame));
128	frame.sf_signum = sig;
129
130	/* Save register context. */
131	for (i=0; i < 7; i++)
132		frame.sf_sc.sc_t[i] = tf->tf_t[i];
133	for (i=0; i < 12; i++)
134		frame.sf_sc.sc_s[i] = tf->tf_s[i];
135	for (i=0; i < 8; i++)
136		frame.sf_sc.sc_a[i] = tf->tf_a[i];
137	frame.sf_sc.sc_ra = tf->tf_ra;
138	frame.sf_sc.sc_sp = tf->tf_sp;
139	frame.sf_sc.sc_tp = tf->tf_tp;
140	frame.sf_sc.sc_sepc = tf->tf_sepc;
141
142	/* Save signal mask. */
143	frame.sf_sc.sc_mask = mask;
144
145	/* Copy the saved FPU state into the frame if necessary. */
146	if (p->p_addr->u_pcb.pcb_flags & PCB_FPU) {
147		fpreg = &p->p_addr->u_pcb.pcb_fpstate;
148		for (i = 0; i < 32; i++)
149			frame.sf_sc.sc_f[i] = fpreg->fp_f[i];
150		frame.sf_sc.sc_fcsr = fpreg->fp_fcsr;
151	}
152
153	if (info) {
154		sip = &fp->sf_si;
155		frame.sf_si = *ksip;
156	}
157
158	frame.sf_sc.sc_cookie = (long)&fp->sf_sc ^ p->p_p->ps_sigcookie;
159	if (copyout(&frame, fp, sizeof(frame)) != 0) {
160		/*
161		 * Process has trashed its stack; alert caller which
162		 * will give it an illegal instruction to halt it in
163		 * its tracks.
164		 */
165		return 1;
166	}
167
168
169	/*
170	 * Build context to run handler in.  We invoke the handler
171	 * directly, only returning via the trampoline.
172         */
173	tf->tf_a[0] = sig;
174	tf->tf_a[1] = (register_t)sip;
175	tf->tf_a[2] = (register_t)&fp->sf_sc;
176	tf->tf_ra = p->p_p->ps_sigcode;
177	tf->tf_sp = (register_t)fp;
178
179	tf->tf_sepc = (register_t)catcher;
180
181	return 0;
182}
183
184/*
185 * System call to cleanup state after a signal
186 * has been taken.  Reset signal mask and
187 * stack state from context left by sendsig (above).
188 * Return to previous pc and psl as specified by
189 * context left by sendsig. Check carefully to
190 * make sure that the user has not modified the
191 * psr to gain improper privileges or to cause
192 * a machine fault.
193 */
194
195int
196sys_sigreturn(struct proc *p, void *v, register_t *retval)
197{
198
199	struct sys_sigreturn_args /* {
200		syscallarg(struct sigcontext *) sigcntxp;
201	} */ *uap = v;
202	struct sigcontext ksc, *scp = SCARG(uap, sigcntxp);
203	struct trapframe *tf;
204	struct fpreg     *fpreg;
205	int i;
206
207	if (PROC_PC(p) != p->p_p->ps_sigcoderet) {
208		sigexit(p, SIGILL);
209		return (EPERM);
210	}
211
212	if (copyin(scp, &ksc, sizeof(*scp)) != 0)
213		return (EFAULT);
214
215	if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) {
216		sigexit(p, SIGILL);
217		return (EFAULT);
218	}
219
220	/* Prevent reuse of the sigcontext cookie */
221	ksc.sc_cookie = 0;
222	(void)copyout(&ksc.sc_cookie, (caddr_t)scp +
223	    offsetof(struct sigcontext, sc_cookie), sizeof (ksc.sc_cookie));
224
225	/* Restore register context. */
226	tf = process_frame(p);
227	for (i=0; i < 7; i++)
228		tf->tf_t[i] = ksc.sc_t[i];
229	for (i=0; i < 12; i++)
230		tf->tf_s[i] = ksc.sc_s[i];
231	for (i=0; i < 8; i++)
232		tf->tf_a[i] = ksc.sc_a[i];
233	tf->tf_ra = ksc.sc_ra;
234	tf->tf_sp = ksc.sc_sp;
235	tf->tf_tp = ksc.sc_tp;
236	tf->tf_sepc = ksc.sc_sepc;
237
238	/* Write saved FPU state back to PCB if necessary. */
239	if (p->p_addr->u_pcb.pcb_flags & PCB_FPU) {
240		fpreg = &p->p_addr->u_pcb.pcb_fpstate;
241		for (i = 0; i < 32; i++)
242			fpreg->fp_f[i] = ksc.sc_f[i];
243		fpreg->fp_fcsr = ksc.sc_fcsr;
244
245		/* drop FPU state */
246		tf->tf_sstatus &= ~SSTATUS_FS_MASK;
247		tf->tf_sstatus |= SSTATUS_FS_OFF;
248	}
249
250	/* Restore signal mask. */
251	p->p_sigmask = ksc.sc_mask & ~sigcantmask;
252
253	return (EJUSTRETURN);
254}
255