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