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