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 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 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 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 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 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 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 306 cpu_spawn_return(struct lwp *l) 307 { 308 309 userret(l, l->l_md.md_tf->tf_pc, 0); 310 } 311