1 /* $NetBSD: m68k_syscall.c,v 1.55 2023/10/05 19:41:04 ad Exp $ */ 2 3 /*- 4 * Portions Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright (c) 1988 University of Utah. 31 * Copyright (c) 1982, 1986, 1990, 1993 32 * The Regents of the University of California. All rights reserved. 33 * 34 * This code is derived from software contributed to Berkeley by 35 * the Systems Programming Group of the University of Utah Computer 36 * Science Department. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. Neither the name of the University nor the names of its contributors 47 * may be used to endorse or promote products derived from this software 48 * without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 * 62 * from: Utah $Hdr: trap.c 1.37 92/12/20$ 63 * 64 * @(#)trap.c 8.5 (Berkeley) 1/4/94 65 */ 66 67 #include <sys/cdefs.h> 68 __KERNEL_RCSID(0, "$NetBSD: m68k_syscall.c,v 1.55 2023/10/05 19:41:04 ad Exp $"); 69 70 #include "opt_execfmt.h" 71 #include "opt_compat_netbsd.h" 72 #include "opt_compat_aout_m68k.h" 73 74 #include <sys/param.h> 75 #include <sys/systm.h> 76 #include <sys/proc.h> 77 #include <sys/kmem.h> 78 #include <sys/acct.h> 79 #include <sys/kernel.h> 80 #include <sys/syscall.h> 81 #include <sys/syscallvar.h> 82 #include <sys/syslog.h> 83 #include <sys/ktrace.h> 84 85 #include <machine/psl.h> 86 #include <machine/cpu.h> 87 #include <machine/reg.h> 88 89 #include <uvm/uvm_extern.h> 90 91 /* 92 * Defined in machine-specific code (usually trap.c) 93 * XXX: This will disappear when all m68k ports share common trap() code... 94 */ 95 extern void machine_userret(struct lwp *, struct frame *, u_quad_t); 96 97 void syscall(register_t, struct frame); 98 99 void aoutm68k_syscall_intern(struct proc *); 100 static void syscall_plain(register_t, struct lwp *, struct frame *); 101 static void syscall_fancy(register_t, struct lwp *, struct frame *); 102 103 104 /* 105 * Process a system call. 106 */ 107 void 108 syscall(register_t code, struct frame frame) 109 { 110 struct lwp *l; 111 struct proc *p; 112 u_quad_t sticks; 113 114 curcpu()->ci_data.cpu_nsyscall++; 115 if (!USERMODE(frame.f_sr)) 116 panic("syscall"); 117 118 l = curlwp; 119 p = l->l_proc; 120 sticks = p->p_sticks; 121 l->l_md.md_regs = frame.f_regs; 122 123 (p->p_md.md_syscall)(code, l, &frame); 124 125 machine_userret(l, &frame, sticks); 126 } 127 128 void 129 syscall_intern(struct proc *p) 130 { 131 132 if (trace_is_enabled(p)) 133 p->p_md.md_syscall = syscall_fancy; 134 else 135 p->p_md.md_syscall = syscall_plain; 136 } 137 138 /* 139 * Not worth the effort of a whole new set of syscall_{plain,fancy} functions 140 */ 141 void 142 aoutm68k_syscall_intern(struct proc *p) 143 { 144 145 if (trace_is_enabled(p)) 146 p->p_md.md_syscall = syscall_fancy; 147 else 148 p->p_md.md_syscall = syscall_plain; 149 } 150 151 static void 152 syscall_plain(register_t code, struct lwp *l, struct frame *frame) 153 { 154 char *params; 155 const struct sysent *callp; 156 int error, nsys; 157 size_t argsize; 158 register_t args[16], rval[2]; 159 struct proc *p = l->l_proc; 160 161 nsys = p->p_emul->e_nsysent; 162 callp = p->p_emul->e_sysent; 163 164 params = (char *)frame->f_regs[SP] + sizeof(int); 165 166 switch (code) { 167 case SYS_syscall: 168 /* 169 * Code is first argument, followed by actual args. 170 */ 171 error = ufetch_long((void *)params, (u_long *)&code); 172 if (error) 173 goto bad; 174 params += sizeof(int); 175 #if defined(COMPAT_13) || defined(COMPAT_16) 176 /* 177 * XXX sigreturn requires special stack manipulation 178 * that is only done if entered via the sigreturn 179 * trap. Cannot allow it here so make sure we fail. 180 */ 181 switch (code) { 182 #ifdef COMPAT_13 183 case SYS_compat_13_sigreturn13: 184 #endif 185 #ifdef COMPAT_16 186 case SYS_compat_16___sigreturn14: 187 #endif 188 code = nsys; 189 break; 190 } 191 #endif 192 break; 193 case SYS___syscall: 194 /* 195 * Like syscall, but code is a quad, so as to maintain 196 * quad alignment for the rest of the arguments. 197 */ 198 error = ufetch_long((void *)(params + 199 _QUAD_LOWWORD * sizeof(int)), 200 (u_long *)&code); 201 if (error) 202 goto bad; 203 params += sizeof(quad_t); 204 break; 205 default: 206 break; 207 } 208 209 if (code < 0 || code >= nsys) 210 callp += p->p_emul->e_nosys; /* illegal */ 211 else 212 callp += code; 213 214 argsize = callp->sy_argsize; 215 if (argsize) { 216 error = copyin(params, (void *)args, argsize); 217 if (error) 218 goto bad; 219 } 220 221 rval[0] = 0; 222 rval[1] = frame->f_regs[D1]; 223 error = sy_call(callp, l, args, rval); 224 225 switch (error) { 226 case 0: 227 /* 228 * Reinitialize proc pointer `p' as it may be different 229 * if this is a child returning from fork syscall. 230 */ 231 l = curlwp; 232 p = l->l_proc; 233 frame->f_regs[D0] = rval[0]; 234 frame->f_regs[D1] = rval[1]; 235 frame->f_sr &= ~PSL_C; /* carry bit */ 236 #ifdef COMPAT_50 237 /* 238 * Starting with the 5.0 release all libc assembler 239 * stubs properly handle returning pointers in %a0 240 * themselves, so no need to copy the syscall return 241 * value there. However, -current binaries post 4.0 242 * but pre-5.0 might still require this copy, so we 243 * select this behaviour based on COMPAT_50 as we have 244 * no equivalent for the exact in-between version. 245 */ 246 247 /* 248 * Some pre-m68k ELF libc assembler stubs assume 249 * %a0 is preserved across system calls... 250 */ 251 if (p->p_emul == &emul_netbsd) 252 frame->f_regs[A0] = rval[0]; 253 #endif 254 break; 255 case ERESTART: 256 /* 257 * We always enter through a `trap' instruction, which is 2 258 * bytes, so adjust the pc by that amount. 259 */ 260 frame->f_pc = frame->f_pc - 2; 261 break; 262 case EJUSTRETURN: 263 /* nothing to do */ 264 break; 265 default: 266 bad: 267 /* 268 * XXX: SVR4 uses this code-path, so we may have 269 * to translate errno. XXX OBSOLETE 270 */ 271 if (p->p_emul->e_errno) 272 error = p->p_emul->e_errno[error]; 273 frame->f_regs[D0] = error; 274 frame->f_sr |= PSL_C; /* carry bit */ 275 break; 276 } 277 } 278 279 static void 280 syscall_fancy(register_t code, struct lwp *l, struct frame *frame) 281 { 282 char *params; 283 const struct sysent *callp; 284 int error, nsys; 285 size_t argsize; 286 register_t args[16], rval[2]; 287 struct proc *p = l->l_proc; 288 289 nsys = p->p_emul->e_nsysent; 290 callp = p->p_emul->e_sysent; 291 292 params = (char *)frame->f_regs[SP] + sizeof(int); 293 294 switch (code) { 295 case SYS_syscall: 296 /* 297 * Code is first argument, followed by actual args. 298 */ 299 error = ufetch_long((void *)params, (u_long *)&code); 300 if (error) 301 goto bad; 302 params += sizeof(int); 303 #if defined(COMPAT_13) || defined(COMPAT_16) 304 /* 305 * XXX sigreturn requires special stack manipulation 306 * that is only done if entered via the sigreturn 307 * trap. Cannot allow it here so make sure we fail. 308 */ 309 switch (code) { 310 #ifdef COMPAT_13 311 case SYS_compat_13_sigreturn13: 312 #endif 313 #ifdef COMPAT_16 314 case SYS_compat_16___sigreturn14: 315 #endif 316 code = nsys; 317 break; 318 } 319 #endif 320 break; 321 case SYS___syscall: 322 /* 323 * Like syscall, but code is a quad, so as to maintain 324 * quad alignment for the rest of the arguments. 325 */ 326 error = ufetch_long((void *)(params + 327 _QUAD_LOWWORD * sizeof(int)), 328 (u_long *)&code); 329 if (error) 330 goto bad; 331 params += sizeof(quad_t); 332 break; 333 default: 334 break; 335 } 336 337 if (code < 0 || code >= nsys) 338 callp += p->p_emul->e_nosys; /* illegal */ 339 else 340 callp += code; 341 342 argsize = callp->sy_argsize; 343 if (argsize) { 344 error = copyin(params, (void *)args, argsize); 345 if (error) 346 goto bad; 347 } 348 349 if ((error = trace_enter(code, callp, args)) != 0) 350 goto out; 351 352 rval[0] = 0; 353 rval[1] = frame->f_regs[D1]; 354 error = sy_call(callp, l, args, rval); 355 out: 356 switch (error) { 357 case 0: 358 /* 359 * Reinitialize lwp/proc pointers as they may be different 360 * if this is a child returning from fork syscall. 361 */ 362 l = curlwp; 363 p = l->l_proc; 364 frame->f_regs[D0] = rval[0]; 365 frame->f_regs[D1] = rval[1]; 366 frame->f_sr &= ~PSL_C; /* carry bit */ 367 #ifdef COMPAT_50 368 /* see syscall_plain for a comment explaining this */ 369 370 /* 371 * Some pre-m68k ELF libc assembler stubs assume 372 * %a0 is preserved across system calls... 373 */ 374 if (p->p_emul == &emul_netbsd) 375 frame->f_regs[A0] = rval[0]; 376 #endif 377 break; 378 case ERESTART: 379 /* 380 * We always enter through a `trap' instruction, which is 2 381 * bytes, so adjust the pc by that amount. 382 */ 383 frame->f_pc = frame->f_pc - 2; 384 break; 385 case EJUSTRETURN: 386 /* nothing to do */ 387 break; 388 default: 389 bad: 390 /* 391 * XXX: SVR4 uses this code-path, so we may have 392 * to translate errno. 393 */ 394 if (p->p_emul->e_errno) 395 error = p->p_emul->e_errno[error]; 396 frame->f_regs[D0] = error; 397 frame->f_sr |= PSL_C; /* carry bit */ 398 break; 399 } 400 401 trace_exit(code, callp, args, rval, error); 402 } 403 404 void 405 md_child_return(struct lwp *l) 406 { 407 /* See cpu_lwp_fork() */ 408 struct frame *f = (struct frame *)l->l_md.md_regs; 409 410 f->f_regs[D0] = 0; 411 f->f_sr &= ~PSL_C; 412 f->f_format = FMT0; 413 414 machine_userret(l, f, 0); 415 } 416 417 /* 418 * Start a new LWP 419 */ 420 void 421 startlwp(void *arg) 422 { 423 ucontext_t *uc = arg; 424 lwp_t *l = curlwp; 425 struct frame *f = (struct frame *)l->l_md.md_regs; 426 int error __diagused; 427 428 f->f_regs[D0] = 0; 429 f->f_sr &= ~PSL_C; 430 f->f_format = FMT0; 431 432 error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags); 433 KASSERT(error == 0); 434 435 kmem_free(uc, sizeof(ucontext_t)); 436 machine_userret(l, f, 0); 437 } 438 439 /* 440 * Process the tail end of a posix_spawn() for the child. 441 */ 442 void 443 cpu_spawn_return(struct lwp *l) 444 { 445 struct frame *f = (struct frame *)l->l_md.md_regs; 446 447 machine_userret(l, f, 0); 448 } 449