1 /*	$NetBSD: sunos_machdep.c,v 1.16 2002/07/04 23:32:07 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Matthew R. Green
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #ifdef _KERNEL_OPT
32 #include "opt_ddb.h"
33 #endif
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/proc.h>
38 #include <sys/namei.h>
39 #include <sys/user.h>
40 #include <sys/filedesc.h>
41 #include <sys/ioctl.h>
42 #include <sys/mount.h>
43 #include <sys/kernel.h>
44 #include <sys/signal.h>
45 #include <sys/signalvar.h>
46 #include <sys/malloc.h>
47 
48 #include <sys/syscallargs.h>
49 #include <compat/sunos/sunos.h>
50 #include <compat/sunos/sunos_syscallargs.h>
51 
52 #include <machine/frame.h>
53 #include <machine/cpu.h>
54 
55 #ifdef DEBUG
56 #include <sparc64/sparc64/sigdebug.h>
57 #endif
58 
59 struct sunos_sigcontext {
60 	int	sc_onstack;		/* sigstack state to restore */
61 	int	sc_mask;		/* signal mask to restore (old style) */
62 	/* begin machine dependent portion */
63 	int	sc_sp;			/* %sp to restore */
64 	int	sc_pc;			/* pc to restore */
65 	int	sc_npc;			/* npc to restore */
66 	int	sc_psr;			/* pstate to restore */
67 	int	sc_g1;			/* %g1 to restore */
68 	int	sc_o0;			/* %o0 to restore */
69 };
70 
71 struct sunos_sigframe {
72 	int	sf_signo;		/* signal number */
73 	int	sf_code;		/* code */
74 	u_int32_t	sf_scp;			/* SunOS user addr of sigcontext */
75 	int	sf_addr;		/* SunOS compat, always 0 for now */
76 	struct	sunos_sigcontext sf_sc;	/* actual sigcontext */
77 };
78 
79 void
80 sunos_sendsig(sig, mask, code)
81 	int sig;
82 	sigset_t *mask;
83 	u_long code;
84 {
85 	register struct proc *p = curproc;
86 	register struct sunos_sigframe *fp;
87 	register struct trapframe64 *tf;
88 	register int addr, onstack;
89 	struct rwindow32 *kwin, *oldsp, *newsp;
90 	sig_t catcher = SIGACTION(p, sig).sa_handler;
91 	struct sunos_sigframe sf;
92 
93 	tf = p->p_md.md_tf;
94 	/* Need to attempt to zero extend this 32-bit pointer */
95 	oldsp = (struct rwindow32 *)(u_long)(u_int)tf->tf_out[6];
96 	/*
97 	 * Compute new user stack addresses, subtract off
98 	 * one signal frame, and align.
99 	 */
100 	onstack =
101 	    (p->p_sigctx.ps_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
102 	    (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;
103 
104 	if (onstack)
105 		fp = (struct sunos_sigframe *)((char *)p->p_sigctx.ps_sigstk.ss_sp +
106 					p->p_sigctx.ps_sigstk.ss_size);
107 	else
108 		fp = (struct sunos_sigframe *)oldsp;
109 	fp = (struct sunos_sigframe *)((long)(fp - 1) & ~7);
110 
111 #ifdef DEBUG
112 	sigpid = p->p_pid;
113 	if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) {
114 		printf("sunos_sendsig: %s[%d] sig %d newusp %p scp %p oldsp %p\n",
115 		    p->p_comm, p->p_pid, sig, fp, &fp->sf_sc, oldsp);
116 #ifdef DDB
117 		if (sigdebug & SDB_DDB) Debugger();
118 #endif
119 	}
120 #endif
121 	/*
122 	 * Now set up the signal frame.  We build it in kernel space
123 	 * and then copy it out.  We probably ought to just build it
124 	 * directly in user space....
125 	 */
126 	sf.sf_signo = sig;
127 	sf.sf_code = code;
128 	sf.sf_scp = (u_long)&fp->sf_sc;
129 	sf.sf_addr = 0;			/* XXX */
130 
131 	/*
132 	 * Build the signal context to be used by sigreturn.
133 	 */
134 	sf.sf_sc.sc_onstack = p->p_sigctx.ps_sigstk.ss_flags & SS_ONSTACK;
135 	native_sigset_to_sigset13(mask, &sf.sf_sc.sc_mask);
136 	sf.sf_sc.sc_sp = (long)oldsp;
137 	sf.sf_sc.sc_pc = tf->tf_pc;
138 	sf.sf_sc.sc_npc = tf->tf_npc;
139 	sf.sf_sc.sc_psr = TSTATECCR_TO_PSR(tf->tf_tstate); /* XXX */
140 	sf.sf_sc.sc_g1 = tf->tf_global[1];
141 	sf.sf_sc.sc_o0 = tf->tf_out[0];
142 
143 	/*
144 	 * Put the stack in a consistent state before we whack away
145 	 * at it.  Note that write_user_windows may just dump the
146 	 * registers into the pcb; we need them in the process's memory.
147 	 * We also need to make sure that when we start the signal handler,
148 	 * its %i6 (%fp), which is loaded from the newly allocated stack area,
149 	 * joins seamlessly with the frame it was in when the signal occurred,
150 	 * so that the debugger and _longjmp code can back up through it.
151 	 */
152 	newsp = (struct rwindow32 *)((long)fp - sizeof(struct rwindow32));
153 	write_user_windows();
154 #ifdef DEBUG
155 	if ((sigdebug & SDB_KSTACK))
156 	    printf("sunos_sendsig: saving sf to %p, setting stack pointer %p to %p\n",
157 		   fp, &(((struct rwindow32 *)newsp)->rw_in[6]), oldsp);
158 #endif
159 	kwin = (struct rwindow32 *)(((caddr_t)tf)-CCFSZ);
160 	if (rwindow_save(p) ||
161 	    copyout((caddr_t)&sf, (caddr_t)fp, sizeof sf) ||
162 	    suword(&(((struct rwindow32 *)newsp)->rw_in[6]), (u_long)oldsp)) {
163 		/*
164 		 * Process has trashed its stack; give it an illegal
165 		 * instruction to halt it in its tracks.
166 		 */
167 #ifdef DEBUG
168 		if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
169 			printf("sunos_sendsig: window save or copyout error\n");
170 		printf("sunos_sendsig: stack was trashed trying to send sig %d, sending SIGILL\n", sig);
171 #ifdef DDB
172 		if (sigdebug & SDB_DDB) Debugger();
173 #endif
174 #endif
175 		sigexit(p, SIGILL);
176 		/* NOTREACHED */
177 	}
178 
179 #ifdef DEBUG
180 	if (sigdebug & SDB_FOLLOW) {
181 		printf("sunos_sendsig: %s[%d] sig %d scp %p\n",
182 		       p->p_comm, p->p_pid, sig, &fp->sf_sc);
183 	}
184 #endif
185 	/*
186 	 * Arrange to continue execution at the code copied out in exec().
187 	 * It needs the function to call in %g1, and a new stack pointer.
188 	 */
189 	addr = (long)catcher;	/* user does his own trampolining */
190 	tf->tf_pc = addr;
191 	tf->tf_npc = addr + 4;
192 	tf->tf_out[6] = (u_int64_t)(u_int)(u_long)newsp;
193 #ifdef DEBUG
194 	if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) {
195 		printf("sunos_sendsig: about to return to catcher %p thru %p\n",
196 		       catcher, (void *)(u_long)addr);
197 #ifdef DDB
198 		if (sigdebug & SDB_DDB) Debugger();
199 #endif
200 	}
201 #endif
202 }
203 
204 int
205 sunos_sys_sigreturn(p, v, retval)
206         register struct proc *p;
207 	void *v;
208 	register_t *retval;
209 {
210 	struct sunos_sys_sigreturn_args /*
211 		syscallarg(struct sigcontext13 *) sigcntxp;
212 	} */ *uap = v;
213 	struct sunos_sigcontext sc, *scp;
214 	sigset_t mask;
215 	struct trapframe64 *tf;
216 
217 	/* First ensure consistent stack state (see sendsig). */
218 	write_user_windows();
219 	if (rwindow_save(p))
220 		sigexit(p, SIGILL);
221 #ifdef DEBUG
222 	if (sigdebug & SDB_FOLLOW) {
223 		printf("sunos_sigreturn: %s[%d], sigcntxp %p\n",
224 		    p->p_comm, p->p_pid, SCARG(uap, sigcntxp));
225 #ifdef DDB
226 		if (sigdebug & SDB_DDB) Debugger();
227 #endif
228 	}
229 #endif
230 
231 	scp = (struct sunos_sigcontext *)SCARG(uap, sigcntxp);
232 	if ((vaddr_t)scp & 3 || (copyin((caddr_t)scp, &sc, sizeof sc) != 0))
233 		return (EFAULT);
234 	scp = &sc;
235 
236 	tf = p->p_md.md_tf;
237 	/*
238 	 * Only the icc bits in the psr are used, so it need not be
239 	 * verified.  pc and npc must be multiples of 4.  This is all
240 	 * that is required; if it holds, just do it.
241 	 */
242 	if (((scp->sc_pc | scp->sc_npc) & 3) != 0 || scp->sc_pc == 0 || scp->sc_npc == 0)
243 #ifdef DEBUG
244 	{
245 		printf("sunos_sigreturn: pc %p or npc %p invalid\n", (void *)(u_long)scp->sc_pc, (void *)(u_long)scp->sc_npc);
246 #ifdef DDB
247 		Debugger();
248 #endif
249 		return (EINVAL);
250 	}
251 #endif
252 		return (EINVAL);
253 	/* take only psr ICC field */
254 	tf->tf_tstate = (int64_t)(tf->tf_tstate & ~TSTATE_CCR) | PSRCC_TO_TSTATE(scp->sc_psr);
255 	tf->tf_pc = scp->sc_pc;
256 	tf->tf_npc = scp->sc_npc;
257 	tf->tf_global[1] = scp->sc_g1;
258 	tf->tf_out[0] = scp->sc_o0;
259 	tf->tf_out[6] = scp->sc_sp;
260 #ifdef DEBUG
261 	if (sigdebug & SDB_FOLLOW) {
262 		printf("sunos_sigreturn: return trapframe pc=%p sp=%p tstate=%llx\n",
263 		       (void *)(u_long)tf->tf_pc, (void *)(u_long)tf->tf_out[6], (unsigned long long)tf->tf_tstate);
264 #ifdef DDB
265 		if (sigdebug & SDB_DDB) Debugger();
266 #endif
267 	}
268 #endif
269 
270 	if (scp->sc_onstack & SS_ONSTACK)
271 		p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK;
272 	else
273 		p->p_sigctx.ps_sigstk.ss_flags &= ~SS_ONSTACK;
274 
275 	/* Restore signal mask */
276 	native_sigset13_to_sigset(&scp->sc_mask, &mask);
277 	(void) sigprocmask1(p, SIG_SETMASK, &mask, 0);
278 
279 	return (EJUSTRETURN);
280 }
281