1 /* $NetBSD: syscall.c,v 1.13 2010/12/20 00:25:43 matt 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_sa.h" 82 83 #include <sys/param.h> 84 #include <sys/systm.h> 85 #include <sys/proc.h> 86 #include <sys/sa.h> 87 #include <sys/savar.h> 88 #include <sys/syscall.h> 89 #include <sys/syscallvar.h> 90 91 #include <sh3/userret.h> 92 93 #include <uvm/uvm_extern.h> 94 95 96 static void syscall_plain(struct lwp *, struct trapframe *); 97 static void syscall_fancy(struct lwp *, struct trapframe *); 98 99 100 void 101 syscall_intern(struct proc *p) 102 { 103 104 if (trace_is_enabled(p)) 105 p->p_md.md_syscall = syscall_fancy; 106 else 107 p->p_md.md_syscall = syscall_plain; 108 } 109 110 111 /* 112 * System call request from POSIX system call gate interface to kernel. 113 * l ... curlwp when trap occurs. 114 * tf ... full user context. 115 */ 116 static void 117 syscall_plain(struct lwp *l, struct trapframe *tf) 118 { 119 struct proc *p = l->l_proc; 120 void *params; 121 const struct sysent *callp; 122 int error, opc, nsys; 123 size_t argsize; 124 register_t code, args[8], rval[2], ocode; 125 126 curcpu()->ci_data.cpu_nsyscall++; 127 128 opc = tf->tf_spc; 129 ocode = code = tf->tf_r0; 130 131 nsys = p->p_emul->e_nsysent; 132 callp = p->p_emul->e_sysent; 133 134 #ifdef KERN_SA 135 if (__predict_false((l->l_savp) 136 && (l->l_savp->savp_pflags & SAVP_FLAG_DELIVERING))) 137 l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING; 138 #endif 139 140 params = (void *)tf->tf_r15; 141 142 switch (code) { 143 case SYS_syscall: 144 /* 145 * Code is first argument, followed by actual args. 146 */ 147 code = tf->tf_r4; /* fuword(params); */ 148 /* params += sizeof(int); */ 149 break; 150 case SYS___syscall: 151 /* 152 * Like syscall, but code is a quad, so as to maintain 153 * quad alignment for the rest of the arguments. 154 */ 155 if (callp != sysent) 156 break; 157 /* fuword(params + _QUAD_LOWWORD * sizeof(int)); */ 158 #if _BYTE_ORDER == BIG_ENDIAN 159 code = tf->tf_r5; 160 #else 161 code = tf->tf_r4; 162 #endif 163 /* params += sizeof(quad_t); */ 164 break; 165 default: 166 break; 167 } 168 if (code < 0 || code >= nsys) 169 callp += p->p_emul->e_nosys; /* illegal */ 170 else 171 callp += code; 172 argsize = callp->sy_argsize; 173 174 if (ocode == SYS_syscall) { 175 if (argsize) { 176 args[0] = tf->tf_r5; 177 args[1] = tf->tf_r6; 178 args[2] = tf->tf_r7; 179 if (argsize > 3 * sizeof(int)) { 180 argsize -= 3 * sizeof(int); 181 error = copyin(params, (void *)&args[3], 182 argsize); 183 } else 184 error = 0; 185 } else 186 error = 0; 187 } 188 else if (ocode == SYS___syscall) { 189 if (argsize) { 190 args[0] = tf->tf_r6; 191 args[1] = tf->tf_r7; 192 if (argsize > 2 * sizeof(int)) { 193 argsize -= 2 * sizeof(int); 194 error = copyin(params, (void *)&args[2], 195 argsize); 196 } else 197 error = 0; 198 } else 199 error = 0; 200 } else { 201 if (argsize) { 202 args[0] = tf->tf_r4; 203 args[1] = tf->tf_r5; 204 args[2] = tf->tf_r6; 205 args[3] = tf->tf_r7; 206 if (argsize > 4 * sizeof(int)) { 207 argsize -= 4 * sizeof(int); 208 error = copyin(params, (void *)&args[4], 209 argsize); 210 } else 211 error = 0; 212 } else 213 error = 0; 214 } 215 216 if (error) 217 goto bad; 218 219 rval[0] = 0; 220 rval[1] = tf->tf_r1; 221 error = sy_call(callp, l, args, rval); 222 223 switch (error) { 224 case 0: 225 tf->tf_r0 = rval[0]; 226 tf->tf_r1 = rval[1]; 227 tf->tf_ssr |= PSL_TBIT; /* T bit */ 228 229 break; 230 case ERESTART: 231 /* 2 = TRAPA instruction size */ 232 tf->tf_spc = opc - 2; 233 234 break; 235 case EJUSTRETURN: 236 /* nothing to do */ 237 break; 238 default: 239 bad: 240 if (p->p_emul->e_errno) 241 error = p->p_emul->e_errno[error]; 242 tf->tf_r0 = error; 243 tf->tf_ssr &= ~PSL_TBIT; /* T bit */ 244 245 break; 246 } 247 248 userret(l); 249 } 250 251 252 /* 253 * Like syscall_plain but with trace_enter/trace_exit. 254 */ 255 static void 256 syscall_fancy(struct lwp *l, struct trapframe *tf) 257 { 258 struct proc *p = l->l_proc; 259 void *params; 260 const struct sysent *callp; 261 int error, opc, nsys; 262 size_t argsize; 263 register_t code, args[8], rval[2], ocode; 264 265 curcpu()->ci_data.cpu_nsyscall++; 266 267 opc = tf->tf_spc; 268 ocode = code = tf->tf_r0; 269 270 nsys = p->p_emul->e_nsysent; 271 callp = p->p_emul->e_sysent; 272 273 #ifdef KERN_SA 274 if (__predict_false((l->l_savp) 275 && (l->l_savp->savp_pflags & SAVP_FLAG_DELIVERING))) 276 l->l_savp->savp_pflags &= ~SAVP_FLAG_DELIVERING; 277 #endif 278 279 params = (void *)tf->tf_r15; 280 281 switch (code) { 282 case SYS_syscall: 283 /* 284 * Code is first argument, followed by actual args. 285 */ 286 code = tf->tf_r4; /* fuword(params); */ 287 /* params += sizeof(int); */ 288 break; 289 case SYS___syscall: 290 /* 291 * Like syscall, but code is a quad, so as to maintain 292 * quad alignment for the rest of the arguments. 293 */ 294 if (callp != sysent) 295 break; 296 /* fuword(params + _QUAD_LOWWORD * sizeof(int)); */ 297 #if _BYTE_ORDER == BIG_ENDIAN 298 code = tf->tf_r5; 299 #else 300 code = tf->tf_r4; 301 #endif 302 /* params += sizeof(quad_t); */ 303 break; 304 default: 305 break; 306 } 307 if (code < 0 || code >= nsys) 308 callp += p->p_emul->e_nosys; /* illegal */ 309 else 310 callp += code; 311 argsize = callp->sy_argsize; 312 313 if (ocode == SYS_syscall) { 314 if (argsize) { 315 args[0] = tf->tf_r5; 316 args[1] = tf->tf_r6; 317 args[2] = tf->tf_r7; 318 if (argsize > 3 * sizeof(int)) { 319 argsize -= 3 * sizeof(int); 320 error = copyin(params, (void *)&args[3], 321 argsize); 322 } else 323 error = 0; 324 } else 325 error = 0; 326 } 327 else if (ocode == SYS___syscall) { 328 if (argsize) { 329 args[0] = tf->tf_r6; 330 args[1] = tf->tf_r7; 331 if (argsize > 2 * sizeof(int)) { 332 argsize -= 2 * sizeof(int); 333 error = copyin(params, (void *)&args[2], 334 argsize); 335 } else 336 error = 0; 337 } else 338 error = 0; 339 } else { 340 if (argsize) { 341 args[0] = tf->tf_r4; 342 args[1] = tf->tf_r5; 343 args[2] = tf->tf_r6; 344 args[3] = tf->tf_r7; 345 if (argsize > 4 * sizeof(int)) { 346 argsize -= 4 * sizeof(int); 347 error = copyin(params, (void *)&args[4], 348 argsize); 349 } else 350 error = 0; 351 } else 352 error = 0; 353 } 354 355 if (error) 356 goto bad; 357 358 if ((error = trace_enter(code, args, callp->sy_narg)) != 0) 359 goto out; 360 361 rval[0] = 0; 362 rval[1] = tf->tf_r1; 363 error = sy_call(callp, l, args, rval); 364 out: 365 switch (error) { 366 case 0: 367 tf->tf_r0 = rval[0]; 368 tf->tf_r1 = rval[1]; 369 tf->tf_ssr |= PSL_TBIT; /* T bit */ 370 371 break; 372 case ERESTART: 373 /* 2 = TRAPA instruction size */ 374 tf->tf_spc = opc - 2; 375 376 break; 377 case EJUSTRETURN: 378 /* nothing to do */ 379 break; 380 default: 381 bad: 382 if (p->p_emul->e_errno) 383 error = p->p_emul->e_errno[error]; 384 tf->tf_r0 = error; 385 tf->tf_ssr &= ~PSL_TBIT; /* T bit */ 386 387 break; 388 } 389 390 391 trace_exit(code, rval, error); 392 393 userret(l); 394 } 395