1 /*	$NetBSD: syscall.c,v 1.29 2015/10/04 08:19:13 joerg Exp $ */
2 
3 /*
4  * Copyright (c) 1996
5  *	The President and Fellows of Harvard College. All rights reserved.
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This software was developed by the Computer Systems Engineering group
10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
11  * contributed to Berkeley.
12  *
13  * All advertising materials mentioning features or use of this software
14  * must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Lawrence Berkeley Laboratory.
17  *	This product includes software developed by Harvard University.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  * 3. All advertising materials mentioning features or use of this software
28  *    must display the following acknowledgement:
29  *	This product includes software developed by the University of
30  *	California, Berkeley and its contributors.
31  *	This product includes software developed by Harvard University.
32  * 4. Neither the name of the University nor the names of its contributors
33  *    may be used to endorse or promote products derived from this software
34  *    without specific prior written permission.
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
37  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
40  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  *
48  *	@(#)trap.c	8.4 (Berkeley) 9/23/93
49  */
50 
51 #include <sys/cdefs.h>
52 __KERNEL_RCSID(0, "$NetBSD: syscall.c,v 1.29 2015/10/04 08:19:13 joerg Exp $");
53 
54 #include "opt_sparc_arch.h"
55 #include "opt_multiprocessor.h"
56 
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/proc.h>
60 #include <sys/signal.h>
61 #include <sys/syscall.h>
62 #include <sys/syscallvar.h>
63 #include <sys/ktrace.h>
64 
65 #include <uvm/uvm_extern.h>
66 
67 #include <sparc/sparc/asm.h>
68 #include <machine/cpu.h>
69 #include <machine/ctlreg.h>
70 #include <machine/trap.h>
71 #include <machine/instr.h>
72 #include <machine/pmap.h>
73 #include <machine/userret.h>
74 
75 #ifdef DDB
76 #include <machine/db_machdep.h>
77 #else
78 #include <machine/frame.h>
79 #endif
80 
81 #include <sparc/fpu/fpu_extern.h>
82 #include <sparc/sparc/memreg.h>
83 #include <sparc/sparc/cpuvar.h>
84 
85 #define MAXARGS	8
86 union args {
87 	uint64_t aligned;
88 	register_t i[MAXARGS];
89 };
90 
91 union rval {
92 	uint64_t aligned;
93 	register_t o[2];
94 };
95 
96 static inline int handle_new(struct trapframe *, register_t *);
97 static inline int getargs(struct proc *p, struct trapframe *,
98     register_t *, const struct sysent **, union args *);
99 #ifdef FPU_DEBUG
100 static inline void save_fpu(struct trapframe *);
101 #endif
102 void syscall(register_t, struct trapframe *, register_t);
103 
104 static inline int
handle_new(struct trapframe * tf,register_t * code)105 handle_new(struct trapframe *tf, register_t *code)
106 {
107 	int new = *code & (SYSCALL_G7RFLAG|SYSCALL_G2RFLAG|SYSCALL_G5RFLAG);
108 	*code &= ~(SYSCALL_G7RFLAG|SYSCALL_G2RFLAG|SYSCALL_G5RFLAG);
109 	return new;
110 }
111 
112 /*
113  * The first six system call arguments are in the six %o registers.
114  * Any arguments beyond that are in the `argument extension' area
115  * of the user's stack frame (see <machine/frame.h>).
116  *
117  * Check for ``special'' codes that alter this, namely syscall and
118  * __syscall.  The latter takes a quad syscall number, so that other
119  * arguments are at their natural alignments.  Adjust the number
120  * of ``easy'' arguments as appropriate; we will copy the hard
121  * ones later as needed.
122  */
123 static inline int
getargs(struct proc * p,struct trapframe * tf,register_t * code,const struct sysent ** callp,union args * args)124 getargs(struct proc *p, struct trapframe *tf, register_t *code,
125     const struct sysent **callp, union args *args)
126 {
127 	int *ap = &tf->tf_out[0];
128 	int error, i, nap = 6;
129 
130 	*callp = p->p_emul->e_sysent;
131 
132 	switch (*code) {
133 	case SYS_syscall:
134 		*code = *ap++;
135 		nap--;
136 		break;
137 	case SYS___syscall:
138 		if (!(p->p_emul->e_flags & EMUL_HAS_SYS___syscall))
139 			break;
140 		*code = ap[_QUAD_LOWWORD];
141 		ap += 2;
142 		nap -= 2;
143 		break;
144 	}
145 
146 	if (*code >= p->p_emul->e_nsysent)
147 		return ENOSYS;
148 
149 	*callp += *code;
150 	i = (*callp)->sy_argsize / sizeof(register_t);
151 	if (__predict_false(i > nap)) {	/* usually false */
152 		void *off = (char *)tf->tf_out[6] +
153 		    offsetof(struct frame, fr_argx);
154 #ifdef DIAGNOSTIC
155 		KASSERT(i <= MAXARGS);
156 #endif
157 		error = copyin(off, &args->i[nap], (i - nap) * sizeof(*ap));
158 		if (error)
159 			return error;
160 		i = nap;
161 	}
162 	copywords(ap, args->i, i * sizeof(*ap));
163 	return 0;
164 }
165 
166 #ifdef FPU_DEBUG
167 static inline void
save_fpu(struct trapframe * tf)168 save_fpu(struct trapframe *tf)
169 {
170 	struct lwp *l = curlwp;
171 
172 	if ((tf->tf_psr & PSR_EF) != 0) {
173 		if (cpuinfo.fplwp != l)
174 			panic("FPU enabled but wrong proc (3) [l=%p, fwlp=%p]",
175 				l, cpuinfo.fplwp);
176 		savefpstate(l->l_md.md_fpstate);
177 		l->l_md.md_fpu = NULL;
178 		cpuinfo.fplwp = NULL;
179 		tf->tf_psr &= ~PSR_EF;
180 		setpsr(getpsr() & ~PSR_EF);
181 	}
182 }
183 #endif
184 
185 void
syscall_intern(struct proc * p)186 syscall_intern(struct proc *p)
187 {
188 
189 	p->p_trace_enabled = trace_is_enabled(p);
190 	p->p_md.md_syscall = syscall;
191 }
192 
193 /*
194  * System calls.  `pc' is just a copy of tf->tf_pc.
195  *
196  * Note that the things labelled `out' registers in the trapframe were the
197  * `in' registers within the syscall trap code (because of the automatic
198  * `save' effect of each trap).  They are, however, the %o registers of the
199  * thing that made the system call, and are named that way here.
200  */
201 void
syscall(register_t code,struct trapframe * tf,register_t pc)202 syscall(register_t code, struct trapframe *tf, register_t pc)
203 {
204 	const struct sysent *callp;
205 	struct proc *p;
206 	struct lwp *l;
207 	int error, new;
208 	union args args;
209 	union rval rval;
210 	register_t i;
211 	u_quad_t sticks;
212 
213 	curcpu()->ci_data.cpu_nsyscall++;	/* XXXSMP */
214 	l = curlwp;
215 	p = l->l_proc;
216 	LWP_CACHE_CREDS(l, p);
217 
218 	sticks = p->p_sticks;
219 	l->l_md.md_tf = tf;
220 
221 #ifdef FPU_DEBUG
222 	save_fpu(tf);
223 #endif
224 	new = handle_new(tf, &code);
225 
226 	if ((error = getargs(p, tf, &code, &callp, &args)) != 0)
227 		goto bad;
228 
229 	rval.o[0] = 0;
230 	rval.o[1] = tf->tf_out[1];
231 
232 	error = sy_invoke(callp, l, args.i, rval.o, code);
233 
234 	switch (error) {
235 	case 0:
236 		/* Note: fork() does not return here in the child */
237 		tf->tf_out[0] = rval.o[0];
238 		tf->tf_out[1] = rval.o[1];
239 		if (new) {
240 			/* jmp %g5, (or %g2 or %g7, deprecated) on success */
241 			if (__predict_true((new & SYSCALL_G5RFLAG) ==
242 					SYSCALL_G5RFLAG))
243 				i = tf->tf_global[5];
244 			else if (new & SYSCALL_G2RFLAG)
245 				i = tf->tf_global[2];
246 			else
247 				i = tf->tf_global[7];
248 			if (i & 3) {
249 				error = EINVAL;
250 				goto bad;
251 			}
252 		} else {
253 			/* old system call convention: clear C on success */
254 			tf->tf_psr &= ~PSR_C;	/* success */
255 			i = tf->tf_npc;
256 		}
257 		tf->tf_pc = i;
258 		tf->tf_npc = i + 4;
259 		break;
260 
261 	case ERESTART:
262 	case EJUSTRETURN:
263 		/* nothing to do */
264 		break;
265 
266 	default:
267 	bad:
268 		if (p->p_emul->e_errno)
269 			error = p->p_emul->e_errno[error];
270 		tf->tf_out[0] = error;
271 		tf->tf_psr |= PSR_C;	/* fail */
272 		i = tf->tf_npc;
273 		tf->tf_pc = i;
274 		tf->tf_npc = i + 4;
275 		break;
276 	}
277 
278 	userret(l, pc, sticks);
279 	share_fpu(l, tf);
280 }
281 
282 /*
283  * Process the tail end of a fork() for the child.
284  */
285 void
child_return(void * arg)286 child_return(void *arg)
287 {
288 	struct lwp *l = arg;
289 
290 	/*
291 	 * Return values in the frame set by cpu_lwp_fork().
292 	 */
293 	userret(l, l->l_md.md_tf->tf_pc, 0);
294 	ktrsysret((l->l_proc->p_lflag & PL_PPWAIT) ? SYS_vfork : SYS_fork,
295 	    0, 0);
296 }
297 
298 /*
299  * Process the tail end of a posix_spawn() for the child.
300  */
301 void
cpu_spawn_return(struct lwp * l)302 cpu_spawn_return(struct lwp *l)
303 {
304 
305 	userret(l, l->l_md.md_tf->tf_pc, 0);
306 }
307 
308