1 /* $NetBSD: syscall.c,v 1.33 2023/10/05 19:41:05 ad 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.33 2023/10/05 19:41:05 ad 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 if (new) {
110 /* jmp %g5, (or %g2 or %g7, deprecated) on success */
111 if (__predict_true((new & SYSCALL_G5RFLAG) == SYSCALL_G5RFLAG))
112 tf->tf_pc = tf->tf_global[5];
113 else if (new & SYSCALL_G2RFLAG)
114 tf->tf_pc = tf->tf_global[2];
115 else
116 tf->tf_pc = tf->tf_global[7];
117 } else {
118 tf->tf_pc = tf->tf_npc;
119 }
120 return new;
121 }
122
123 /*
124 * The first six system call arguments are in the six %o registers.
125 * Any arguments beyond that are in the `argument extension' area
126 * of the user's stack frame (see <machine/frame.h>).
127 *
128 * Check for ``special'' codes that alter this, namely syscall and
129 * __syscall. The latter takes a quad syscall number, so that other
130 * arguments are at their natural alignments. Adjust the number
131 * of ``easy'' arguments as appropriate; we will copy the hard
132 * ones later as needed.
133 */
134 static inline int
getargs(struct proc * p,struct trapframe * tf,register_t * code,const struct sysent ** callp,union args * args)135 getargs(struct proc *p, struct trapframe *tf, register_t *code,
136 const struct sysent **callp, union args *args)
137 {
138 int *ap = &tf->tf_out[0];
139 int error, i, nap = 6;
140
141 *callp = p->p_emul->e_sysent;
142
143 switch (*code) {
144 case SYS_syscall:
145 *code = *ap++;
146 nap--;
147 break;
148 case SYS___syscall:
149 if (!(p->p_emul->e_flags & EMUL_HAS_SYS___syscall))
150 break;
151 *code = ap[_QUAD_LOWWORD];
152 ap += 2;
153 nap -= 2;
154 break;
155 }
156
157 if (*code >= p->p_emul->e_nsysent)
158 return ENOSYS;
159
160 *callp += *code;
161 i = (*callp)->sy_argsize / sizeof(register_t);
162 if (__predict_false(i > nap)) { /* usually false */
163 void *off = (char *)tf->tf_out[6] +
164 offsetof(struct frame, fr_argx);
165 #ifdef DIAGNOSTIC
166 KASSERT(i <= MAXARGS);
167 #endif
168 error = copyin(off, &args->i[nap], (i - nap) * sizeof(*ap));
169 if (error)
170 return error;
171 i = nap;
172 }
173 copywords(ap, args->i, i * sizeof(*ap));
174 return 0;
175 }
176
177 #ifdef FPU_DEBUG
178 static inline void
save_fpu(struct trapframe * tf)179 save_fpu(struct trapframe *tf)
180 {
181 struct lwp *l = curlwp;
182
183 if ((tf->tf_psr & PSR_EF) != 0) {
184 if (cpuinfo.fplwp != l)
185 panic("FPU enabled but wrong proc (3) [l=%p, fwlp=%p]",
186 l, cpuinfo.fplwp);
187 savefpstate(l->l_md.md_fpstate);
188 l->l_md.md_fpu = NULL;
189 cpuinfo.fplwp = NULL;
190 tf->tf_psr &= ~PSR_EF;
191 setpsr(getpsr() & ~PSR_EF);
192 }
193 }
194 #endif
195
196 void
syscall_intern(struct proc * p)197 syscall_intern(struct proc *p)
198 {
199
200 p->p_trace_enabled = trace_is_enabled(p);
201 p->p_md.md_syscall = syscall;
202 }
203
204 /*
205 * System calls. `pc' is just a copy of tf->tf_pc.
206 *
207 * Note that the things labelled `out' registers in the trapframe were the
208 * `in' registers within the syscall trap code (because of the automatic
209 * `save' effect of each trap). They are, however, the %o registers of the
210 * thing that made the system call, and are named that way here.
211 */
212 void
syscall(register_t code,struct trapframe * tf,register_t pc)213 syscall(register_t code, struct trapframe *tf, register_t pc)
214 {
215 const struct sysent *callp;
216 struct proc *p;
217 struct lwp *l;
218 int error, new;
219 union args args;
220 union rval rval;
221 int opc, onpc;
222 u_quad_t sticks;
223
224 curcpu()->ci_data.cpu_nsyscall++; /* XXXSMP */
225 l = curlwp;
226 p = l->l_proc;
227
228 sticks = p->p_sticks;
229 l->l_md.md_tf = tf;
230
231 #ifdef FPU_DEBUG
232 save_fpu(tf);
233 #endif
234
235 /*
236 * save pc/npc in case of ERESTART
237 * adjust pc/npc to new values
238 */
239 opc = tf->tf_pc;
240 onpc = tf->tf_npc;
241
242 new = handle_new(tf, &code);
243
244 tf->tf_npc = tf->tf_pc + 4;
245
246 if ((error = getargs(p, tf, &code, &callp, &args)) != 0)
247 goto bad;
248
249 rval.o[0] = 0;
250 rval.o[1] = tf->tf_out[1];
251
252 error = sy_invoke(callp, l, args.i, rval.o, code);
253
254 switch (error) {
255 case 0:
256 /* Note: fork() does not return here in the child */
257 tf->tf_out[0] = rval.o[0];
258 tf->tf_out[1] = rval.o[1];
259 if (!new) {
260 /* old system call convention: clear C on success */
261 tf->tf_psr &= ~PSR_C; /* success */
262 }
263 break;
264
265 case ERESTART:
266 tf->tf_pc = opc;
267 tf->tf_npc = onpc;
268 break;
269
270 case EJUSTRETURN:
271 /* nothing to do */
272 break;
273
274 default:
275 bad:
276 if (p->p_emul->e_errno)
277 error = p->p_emul->e_errno[error];
278 tf->tf_out[0] = error;
279 tf->tf_psr |= PSR_C; /* fail */
280 tf->tf_pc = onpc;
281 tf->tf_npc = tf->tf_pc + 4;
282 break;
283 }
284
285 userret(l, pc, sticks);
286 share_fpu(l, tf);
287 }
288
289 /*
290 * Process the tail end of a fork() for the child.
291 */
292 void
md_child_return(struct lwp * l)293 md_child_return(struct lwp *l)
294 {
295
296 /*
297 * Return values in the frame set by cpu_lwp_fork().
298 */
299 userret(l, l->l_md.md_tf->tf_pc, 0);
300 }
301
302 /*
303 * Process the tail end of a posix_spawn() for the child.
304 */
305 void
cpu_spawn_return(struct lwp * l)306 cpu_spawn_return(struct lwp *l)
307 {
308
309 userret(l, l->l_md.md_tf->tf_pc, 0);
310 }
311