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