1 /* $NetBSD: syscall.c,v 1.2 2005/12/11 12:19:00 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. All rights reserved. 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the University of Utah, and William Jolitz. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)trap.c 7.4 (Berkeley) 5/13/91 36 */ 37 38 /*- 39 * Copyright (c) 1995 Charles M. Hannum. All rights reserved. 40 * 41 * This code is derived from software contributed to Berkeley by 42 * the University of Utah, and William Jolitz. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: 54 * This product includes software developed by the University of 55 * California, Berkeley and its contributors. 56 * 4. Neither the name of the University nor the names of its contributors 57 * may be used to endorse or promote products derived from this software 58 * without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70 * SUCH DAMAGE. 71 * 72 * @(#)trap.c 7.4 (Berkeley) 5/13/91 73 */ 74 75 /* 76 * SH3 Trap and System call handling 77 * 78 * T.Horiuchi 1998.06.8 79 */ 80 81 #include "opt_ktrace.h" 82 #include "opt_syscall_debug.h" 83 #include "opt_systrace.h" 84 85 #include <sys/param.h> 86 #include <sys/systm.h> 87 #include <sys/proc.h> 88 #include <sys/sa.h> 89 #include <sys/savar.h> 90 #ifdef KTRACE 91 #include <sys/ktrace.h> 92 #endif 93 #ifdef SYSTRACE 94 #include <sys/systrace.h> 95 #endif 96 #include <sys/syscall.h> 97 98 #include <sh3/userret.h> 99 100 #include <uvm/uvm_extern.h> 101 102 103 static void syscall_plain(struct lwp *, struct trapframe *); 104 #if defined(KTRACE) || defined(SYSTRACE) 105 static void syscall_fancy(struct lwp *, struct trapframe *); 106 #endif 107 108 109 void 110 syscall_intern(struct proc *p) 111 { 112 113 #ifdef KTRACE 114 if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) { 115 p->p_md.md_syscall = syscall_fancy; 116 return; 117 } 118 #endif 119 #ifdef SYSTRACE 120 if (ISSET(p->p_flag, P_SYSTRACE)) { 121 p->p_md.md_syscall = syscall_fancy; 122 return; 123 } 124 #endif 125 p->p_md.md_syscall = syscall_plain; 126 } 127 128 129 /* 130 * System call request from POSIX system call gate interface to kernel. 131 * l ... curlwp when trap occurs. 132 * tf ... full user context. 133 */ 134 static void 135 syscall_plain(struct lwp *l, struct trapframe *tf) 136 { 137 struct proc *p = l->l_proc; 138 caddr_t params; 139 const struct sysent *callp; 140 int error, opc, nsys; 141 size_t argsize; 142 register_t code, args[8], rval[2], ocode; 143 144 uvmexp.syscalls++; 145 146 opc = tf->tf_spc; 147 ocode = code = tf->tf_r0; 148 149 nsys = p->p_emul->e_nsysent; 150 callp = p->p_emul->e_sysent; 151 152 params = (caddr_t)tf->tf_r15; 153 154 switch (code) { 155 case SYS_syscall: 156 /* 157 * Code is first argument, followed by actual args. 158 */ 159 code = tf->tf_r4; /* fuword(params); */ 160 /* params += sizeof(int); */ 161 break; 162 case SYS___syscall: 163 /* 164 * Like syscall, but code is a quad, so as to maintain 165 * quad alignment for the rest of the arguments. 166 */ 167 if (callp != sysent) 168 break; 169 /* fuword(params + _QUAD_LOWWORD * sizeof(int)); */ 170 #if _BYTE_ORDER == BIG_ENDIAN 171 code = tf->tf_r5; 172 #else 173 code = tf->tf_r4; 174 #endif 175 /* params += sizeof(quad_t); */ 176 break; 177 default: 178 break; 179 } 180 if (code < 0 || code >= nsys) 181 callp += p->p_emul->e_nosys; /* illegal */ 182 else 183 callp += code; 184 argsize = callp->sy_argsize; 185 186 if (ocode == SYS_syscall) { 187 if (argsize) { 188 args[0] = tf->tf_r5; 189 args[1] = tf->tf_r6; 190 args[2] = tf->tf_r7; 191 if (argsize > 3 * sizeof(int)) { 192 argsize -= 3 * sizeof(int); 193 error = copyin(params, (caddr_t)&args[3], 194 argsize); 195 } else 196 error = 0; 197 } else 198 error = 0; 199 } 200 else if (ocode == SYS___syscall) { 201 if (argsize) { 202 args[0] = tf->tf_r6; 203 args[1] = tf->tf_r7; 204 if (argsize > 2 * sizeof(int)) { 205 argsize -= 2 * sizeof(int); 206 error = copyin(params, (caddr_t)&args[2], 207 argsize); 208 } else 209 error = 0; 210 } else 211 error = 0; 212 } else { 213 if (argsize) { 214 args[0] = tf->tf_r4; 215 args[1] = tf->tf_r5; 216 args[2] = tf->tf_r6; 217 args[3] = tf->tf_r7; 218 if (argsize > 4 * sizeof(int)) { 219 argsize -= 4 * sizeof(int); 220 error = copyin(params, (caddr_t)&args[4], 221 argsize); 222 } else 223 error = 0; 224 } else 225 error = 0; 226 } 227 228 if (error) 229 goto bad; 230 231 rval[0] = 0; 232 rval[1] = tf->tf_r1; 233 error = (*callp->sy_call)(l, args, rval); 234 235 switch (error) { 236 case 0: 237 tf->tf_r0 = rval[0]; 238 tf->tf_r1 = rval[1]; 239 tf->tf_ssr |= PSL_TBIT; /* T bit */ 240 241 break; 242 case ERESTART: 243 /* 2 = TRAPA instruction size */ 244 tf->tf_spc = opc - 2; 245 246 break; 247 case EJUSTRETURN: 248 /* nothing to do */ 249 break; 250 default: 251 bad: 252 if (p->p_emul->e_errno) 253 error = p->p_emul->e_errno[error]; 254 tf->tf_r0 = error; 255 tf->tf_ssr &= ~PSL_TBIT; /* T bit */ 256 257 break; 258 } 259 260 userret(l); 261 } 262 263 264 #if defined(KTRACE) || defined(SYSTRACE) 265 /* 266 * Like syscall_plain but with trace_enter/trace_exit. 267 */ 268 static void 269 syscall_fancy(struct lwp *l, struct trapframe *tf) 270 { 271 struct proc *p = l->l_proc; 272 caddr_t params; 273 const struct sysent *callp; 274 int error, opc, nsys; 275 size_t argsize; 276 register_t code, args[8], rval[2], ocode; 277 278 uvmexp.syscalls++; 279 280 opc = tf->tf_spc; 281 ocode = code = tf->tf_r0; 282 283 nsys = p->p_emul->e_nsysent; 284 callp = p->p_emul->e_sysent; 285 286 params = (caddr_t)tf->tf_r15; 287 288 switch (code) { 289 case SYS_syscall: 290 /* 291 * Code is first argument, followed by actual args. 292 */ 293 code = tf->tf_r4; /* fuword(params); */ 294 /* params += sizeof(int); */ 295 break; 296 case SYS___syscall: 297 /* 298 * Like syscall, but code is a quad, so as to maintain 299 * quad alignment for the rest of the arguments. 300 */ 301 if (callp != sysent) 302 break; 303 /* fuword(params + _QUAD_LOWWORD * sizeof(int)); */ 304 #if _BYTE_ORDER == BIG_ENDIAN 305 code = tf->tf_r5; 306 #else 307 code = tf->tf_r4; 308 #endif 309 /* params += sizeof(quad_t); */ 310 break; 311 default: 312 break; 313 } 314 if (code < 0 || code >= nsys) 315 callp += p->p_emul->e_nosys; /* illegal */ 316 else 317 callp += code; 318 argsize = callp->sy_argsize; 319 320 if (ocode == SYS_syscall) { 321 if (argsize) { 322 args[0] = tf->tf_r5; 323 args[1] = tf->tf_r6; 324 args[2] = tf->tf_r7; 325 if (argsize > 3 * sizeof(int)) { 326 argsize -= 3 * sizeof(int); 327 error = copyin(params, (caddr_t)&args[3], 328 argsize); 329 } else 330 error = 0; 331 } else 332 error = 0; 333 } 334 else if (ocode == SYS___syscall) { 335 if (argsize) { 336 args[0] = tf->tf_r6; 337 args[1] = tf->tf_r7; 338 if (argsize > 2 * sizeof(int)) { 339 argsize -= 2 * sizeof(int); 340 error = copyin(params, (caddr_t)&args[2], 341 argsize); 342 } else 343 error = 0; 344 } else 345 error = 0; 346 } else { 347 if (argsize) { 348 args[0] = tf->tf_r4; 349 args[1] = tf->tf_r5; 350 args[2] = tf->tf_r6; 351 args[3] = tf->tf_r7; 352 if (argsize > 4 * sizeof(int)) { 353 argsize -= 4 * sizeof(int); 354 error = copyin(params, (caddr_t)&args[4], 355 argsize); 356 } else 357 error = 0; 358 } else 359 error = 0; 360 } 361 362 if (error) 363 goto bad; 364 365 if ((error = trace_enter(l, code, code, NULL, args)) != 0) 366 goto out; 367 368 rval[0] = 0; 369 rval[1] = tf->tf_r1; 370 error = (*callp->sy_call)(l, args, rval); 371 out: 372 switch (error) { 373 case 0: 374 tf->tf_r0 = rval[0]; 375 tf->tf_r1 = rval[1]; 376 tf->tf_ssr |= PSL_TBIT; /* T bit */ 377 378 break; 379 case ERESTART: 380 /* 2 = TRAPA instruction size */ 381 tf->tf_spc = opc - 2; 382 383 break; 384 case EJUSTRETURN: 385 /* nothing to do */ 386 break; 387 default: 388 bad: 389 if (p->p_emul->e_errno) 390 error = p->p_emul->e_errno[error]; 391 tf->tf_r0 = error; 392 tf->tf_ssr &= ~PSL_TBIT; /* T bit */ 393 394 break; 395 } 396 397 398 trace_exit(l, code, args, rval, error); 399 400 userret(l); 401 } 402 #endif /* KTRACE || SYSTRACE */ 403