xref: /netbsd-src/sys/arch/sparc/sparc/syscall.c (revision 68fa58437753598de948829082f591c269b48777)
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