1 /*	$NetBSD: compat_16_machdep.c,v 1.16 2011/01/18 01:02:55 matt Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5  * Copyright (C) 1995, 1996 TooLs GmbH.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: compat_16_machdep.c,v 1.16 2011/01/18 01:02:55 matt Exp $");
36 
37 #ifdef _KERNEL_OPT
38 #include "opt_compat_netbsd.h"
39 #include "opt_altivec.h"
40 #include "opt_ppcarch.h"
41 #endif
42 
43 #include <sys/param.h>
44 #include <sys/mount.h>
45 #include <sys/proc.h>
46 #include <sys/syscallargs.h>
47 #include <sys/systm.h>
48 #include <sys/ucontext.h>
49 
50 #include <uvm/uvm_extern.h>
51 
52 #include <compat/sys/signal.h>
53 #include <compat/sys/signalvar.h>
54 
55 #include <powerpc/pcb.h>
56 #include <powerpc/fpu.h>
57 
58 /*
59  * Send a signal to process.
60  */
61 void
62 sendsig_sigcontext(const ksiginfo_t *ksi, const sigset_t *mask)
63 {
64 	struct lwp *l = curlwp;
65 	struct proc *p = l->l_proc;
66 	struct sigacts *ps = p->p_sigacts;
67 	struct sigcontext *fp, frame;
68 	struct trapframe *tf;
69 	struct utrapframe *utf = &frame.sc_frame;
70 	int onstack, error;
71 	int sig = ksi->ksi_signo;
72 	u_long code = KSI_TRAPCODE(ksi);
73 	sig_t catcher = SIGACTION(p, sig).sa_handler;
74 
75 	tf = trapframe(l);
76 
77 	/* Do we need to jump onto the signal stack? */
78 	onstack =
79 	    (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
80 	    (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;
81 
82 	/* Allocate space for the signal handler context. */
83 	if (onstack)
84 		fp = (struct sigcontext *)((char *)l->l_sigstk.ss_sp +
85 						l->l_sigstk.ss_size);
86 	else
87 		fp = (struct sigcontext *)tf->tf_fixreg[1];
88 	fp = (struct sigcontext *)((uintptr_t)(fp - 1) & -CALLFRAMELEN);
89 
90 	/* Save register context. */
91 	memcpy(utf->fixreg, tf->tf_fixreg, sizeof(utf->fixreg));
92 	utf->lr   = tf->tf_lr;
93 	utf->cr   = tf->tf_cr;
94 	utf->xer  = tf->tf_xer;
95 	utf->ctr  = tf->tf_ctr;
96 	utf->srr0 = tf->tf_srr0;
97 	utf->srr1 = tf->tf_srr1 & PSL_USERSRR1;
98 
99 #ifdef PPC_HAVE_FPU
100 	const struct pcb * const pcb = lwp_getpcb(l);
101 	utf->srr1 |= pcb->pcb_flags & (PCB_FE0|PCB_FE1);
102 #endif
103 #if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
104 	utf->srr1 |= l->l_md.md_flags & MDLWP_USEDVEC ? PSL_VEC : 0;
105 #endif
106 #ifdef PPC_OEA
107 	utf->vrsave = tf->tf_vrsave;
108 	utf->mq = tf->tf_mq;
109 #endif
110 
111 	/* Save signal stack. */
112 	frame.sc_onstack = l->l_sigstk.ss_flags & SS_ONSTACK;
113 
114 	/* Save signal mask. */
115 	frame.sc_mask = *mask;
116 
117 #ifdef COMPAT_13
118 	/*
119 	 * XXX We always have to save an old style signal mask because
120 	 * XXX we might be delivering a signal to a process which will
121 	 * XXX escape from the signal in a non-standard way and invoke
122 	 * XXX sigreturn() directly.
123 	 */
124 	native_sigset_to_sigset13(mask, &frame.__sc_mask13);
125 #endif
126 	sendsig_reset(l, sig);
127 	mutex_exit(p->p_lock);
128 	error = copyout(&frame, fp, sizeof frame);
129 	mutex_enter(p->p_lock);
130 
131 	if (error != 0) {
132 		/*
133 		 * Process has trashed its stack; give it an illegal
134 		 * instructoin to halt it in its tracks.
135 		 */
136 		sigexit(l, SIGILL);
137 		/* NOTREACHED */
138 	}
139 
140 	/*
141 	 * Build context to run handler in.  Note the trampoline version
142 	 * numbers are coordinated with machine-dependent code in libc.
143 	 */
144 	switch (ps->sa_sigdesc[sig].sd_vers) {
145 #if 1 /* COMPAT_16 */
146 	case 0:		/* legacy on-stack sigtramp */
147 		tf->tf_fixreg[1] = (register_t)fp;
148 		tf->tf_lr = (register_t)catcher;
149 		tf->tf_fixreg[3] = (register_t)sig;
150 		tf->tf_fixreg[4] = (register_t)code;
151 		tf->tf_fixreg[5] = (register_t)fp;
152 		tf->tf_srr0 = (register_t)p->p_sigctx.ps_sigcode;
153 		break;
154 #endif /* COMPAT_16 */
155 
156 	case 1:
157 		tf->tf_fixreg[1] = (register_t)fp;
158 		tf->tf_lr = (register_t)catcher;
159 		tf->tf_fixreg[3] = (register_t)sig;
160 		tf->tf_fixreg[4] = (register_t)code;
161 		tf->tf_fixreg[5] = (register_t)fp;
162 		tf->tf_srr0 = (register_t)ps->sa_sigdesc[sig].sd_tramp;
163 		break;
164 
165 	default:
166 		/* Don't know what trampoline version; kill it. */
167 		sigexit(l, SIGILL);
168 	}
169 
170 	/* Remember that we're now on the signal stack. */
171 	if (onstack)
172 		l->l_sigstk.ss_flags |= SS_ONSTACK;
173 }
174 
175 /*
176  * System call to cleanup state after a signal handler returns.
177  */
178 int
179 compat_16_sys___sigreturn14(struct lwp *l,
180     const struct compat_16_sys___sigreturn14_args *uap, register_t *retval)
181 {
182 	/* {
183 		syscallarg(struct sigcontext *) sigcntxp;
184 	} */
185 	struct proc * const p = l->l_proc;
186 	struct sigcontext sc;
187 	struct utrapframe * const utf = &sc.sc_frame;
188 	int error;
189 
190 	/*
191 	 * The trampoline hands us the context.
192 	 * It is unsafe to keep track of it ourselves, in the event that a
193 	 * program jumps out of a signal hander.
194 	 */
195 	if ((error = copyin(SCARG(uap, sigcntxp), &sc, sizeof sc)) != 0)
196 		return (error);
197 
198 	/* Restore the register context. */
199 	struct trapframe * const tf = trapframe(l);
200 
201 	/*
202 	 * Make sure SRR1 hasn't been maliciously tampered with.
203 	 */
204 	if (!PSL_USEROK_P(sc.sc_frame.srr1))
205 		return (EINVAL);
206 
207 	/* Restore register context. */
208 	memcpy(tf->tf_fixreg, utf->fixreg, sizeof(tf->tf_fixreg));
209 	tf->tf_lr   = utf->lr;
210 	tf->tf_cr   = utf->cr;
211 	tf->tf_xer  = utf->xer;
212 	tf->tf_ctr  = utf->ctr;
213 	tf->tf_srr0 = utf->srr0;
214 	tf->tf_srr1 = utf->srr1;
215 
216 #ifdef PPC_HAVE_FPU
217 	struct pcb * const pcb = lwp_getpcb(l);
218 	pcb->pcb_flags &= ~(PCB_FE0|PCB_FE1);
219 	pcb->pcb_flags |= utf->srr1 & (PCB_FE0|PCB_FE1);
220 #endif
221 #ifdef PPC_OEA
222 	tf->tf_vrsave = utf->vrsave;
223 	tf->tf_mq = utf->mq;
224 #endif
225 
226 	mutex_enter(p->p_lock);
227 	/* Restore signal stack. */
228 	if (sc.sc_onstack & SS_ONSTACK)
229 		l->l_sigstk.ss_flags |= SS_ONSTACK;
230 	else
231 		l->l_sigstk.ss_flags &= ~SS_ONSTACK;
232 	/* Restore signal mask. */
233 	(void) sigprocmask1(l, SIG_SETMASK, &sc.sc_mask, 0);
234 	mutex_exit(p->p_lock);
235 
236 	return (EJUSTRETURN);
237 }
238