1 /* $NetBSD: m68k_syscall.c,v 1.56 2026/04/03 14:59:55 thorpej 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.56 2026/04/03 14:59:55 thorpej 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 void syscall(register_t, struct frame); 92 93 void aoutm68k_syscall_intern(struct proc *); 94 static void syscall_plain(register_t, struct lwp *, struct frame *); 95 static void syscall_fancy(register_t, struct lwp *, struct frame *); 96 97 /* 98 * Process a system call. 99 */ 100 void 101 syscall(register_t code, struct frame frame) 102 { 103 struct lwp *l; 104 struct proc *p; 105 u_quad_t sticks; 106 107 curcpu()->ci_data.cpu_nsyscall++; 108 if (!USERMODE(frame.f_sr)) 109 panic("syscall"); 110 111 l = curlwp; 112 p = l->l_proc; 113 sticks = p->p_sticks; 114 l->l_md.md_regs = frame.f_regs; 115 116 (p->p_md.md_syscall)(code, l, &frame); 117 118 userret(l, &frame, sticks); 119 } 120 121 void 122 syscall_intern(struct proc *p) 123 { 124 125 if (trace_is_enabled(p)) 126 p->p_md.md_syscall = syscall_fancy; 127 else 128 p->p_md.md_syscall = syscall_plain; 129 } 130 131 /* 132 * Not worth the effort of a whole new set of syscall_{plain,fancy} functions 133 */ 134 void 135 aoutm68k_syscall_intern(struct proc *p) 136 { 137 138 if (trace_is_enabled(p)) 139 p->p_md.md_syscall = syscall_fancy; 140 else 141 p->p_md.md_syscall = syscall_plain; 142 } 143 144 static void 145 syscall_plain(register_t code, struct lwp *l, struct frame *frame) 146 { 147 char *params; 148 const struct sysent *callp; 149 int error, nsys; 150 size_t argsize; 151 register_t args[16], rval[2]; 152 struct proc *p = l->l_proc; 153 154 nsys = p->p_emul->e_nsysent; 155 callp = p->p_emul->e_sysent; 156 157 params = (char *)frame->f_regs[SP] + sizeof(int); 158 159 switch (code) { 160 case SYS_syscall: 161 /* 162 * Code is first argument, followed by actual args. 163 */ 164 error = ufetch_long((void *)params, (u_long *)&code); 165 if (error) 166 goto bad; 167 params += sizeof(int); 168 #if defined(COMPAT_13) || defined(COMPAT_16) 169 /* 170 * XXX sigreturn requires special stack manipulation 171 * that is only done if entered via the sigreturn 172 * trap. Cannot allow it here so make sure we fail. 173 */ 174 switch (code) { 175 #ifdef COMPAT_13 176 case SYS_compat_13_sigreturn13: 177 #endif 178 #ifdef COMPAT_16 179 case SYS_compat_16___sigreturn14: 180 #endif 181 code = nsys; 182 break; 183 } 184 #endif 185 break; 186 case SYS___syscall: 187 /* 188 * Like syscall, but code is a quad, so as to maintain 189 * quad alignment for the rest of the arguments. 190 */ 191 error = ufetch_long((void *)(params + 192 _QUAD_LOWWORD * sizeof(int)), 193 (u_long *)&code); 194 if (error) 195 goto bad; 196 params += sizeof(quad_t); 197 break; 198 default: 199 break; 200 } 201 202 if (code < 0 || code >= nsys) 203 callp += p->p_emul->e_nosys; /* illegal */ 204 else 205 callp += code; 206 207 argsize = callp->sy_argsize; 208 if (argsize) { 209 error = copyin(params, (void *)args, argsize); 210 if (error) 211 goto bad; 212 } 213 214 rval[0] = 0; 215 rval[1] = frame->f_regs[D1]; 216 error = sy_call(callp, l, args, rval); 217 218 switch (error) { 219 case 0: 220 /* 221 * Reinitialize proc pointer `p' as it may be different 222 * if this is a child returning from fork syscall. 223 */ 224 l = curlwp; 225 p = l->l_proc; 226 frame->f_regs[D0] = rval[0]; 227 frame->f_regs[D1] = rval[1]; 228 frame->f_sr &= ~PSL_C; /* carry bit */ 229 #ifdef COMPAT_50 230 /* 231 * Starting with the 5.0 release all libc assembler 232 * stubs properly handle returning pointers in %a0 233 * themselves, so no need to copy the syscall return 234 * value there. However, -current binaries post 4.0 235 * but pre-5.0 might still require this copy, so we 236 * select this behaviour based on COMPAT_50 as we have 237 * no equivalent for the exact in-between version. 238 */ 239 240 /* 241 * Some pre-m68k ELF libc assembler stubs assume 242 * %a0 is preserved across system calls... 243 */ 244 if (p->p_emul == &emul_netbsd) 245 frame->f_regs[A0] = rval[0]; 246 #endif 247 break; 248 case ERESTART: 249 /* 250 * We always enter through a `trap' instruction, which is 2 251 * bytes, so adjust the pc by that amount. 252 */ 253 frame->f_pc = frame->f_pc - 2; 254 break; 255 case EJUSTRETURN: 256 /* nothing to do */ 257 break; 258 default: 259 bad: 260 /* 261 * XXX: SVR4 uses this code-path, so we may have 262 * to translate errno. XXX OBSOLETE 263 */ 264 if (p->p_emul->e_errno) 265 error = p->p_emul->e_errno[error]; 266 frame->f_regs[D0] = error; 267 frame->f_sr |= PSL_C; /* carry bit */ 268 break; 269 } 270 } 271 272 static void 273 syscall_fancy(register_t code, struct lwp *l, struct frame *frame) 274 { 275 char *params; 276 const struct sysent *callp; 277 int error, nsys; 278 size_t argsize; 279 register_t args[16], rval[2]; 280 struct proc *p = l->l_proc; 281 282 nsys = p->p_emul->e_nsysent; 283 callp = p->p_emul->e_sysent; 284 285 params = (char *)frame->f_regs[SP] + sizeof(int); 286 287 switch (code) { 288 case SYS_syscall: 289 /* 290 * Code is first argument, followed by actual args. 291 */ 292 error = ufetch_long((void *)params, (u_long *)&code); 293 if (error) 294 goto bad; 295 params += sizeof(int); 296 #if defined(COMPAT_13) || defined(COMPAT_16) 297 /* 298 * XXX sigreturn requires special stack manipulation 299 * that is only done if entered via the sigreturn 300 * trap. Cannot allow it here so make sure we fail. 301 */ 302 switch (code) { 303 #ifdef COMPAT_13 304 case SYS_compat_13_sigreturn13: 305 #endif 306 #ifdef COMPAT_16 307 case SYS_compat_16___sigreturn14: 308 #endif 309 code = nsys; 310 break; 311 } 312 #endif 313 break; 314 case SYS___syscall: 315 /* 316 * Like syscall, but code is a quad, so as to maintain 317 * quad alignment for the rest of the arguments. 318 */ 319 error = ufetch_long((void *)(params + 320 _QUAD_LOWWORD * sizeof(int)), 321 (u_long *)&code); 322 if (error) 323 goto bad; 324 params += sizeof(quad_t); 325 break; 326 default: 327 break; 328 } 329 330 if (code < 0 || code >= nsys) 331 callp += p->p_emul->e_nosys; /* illegal */ 332 else 333 callp += code; 334 335 argsize = callp->sy_argsize; 336 if (argsize) { 337 error = copyin(params, (void *)args, argsize); 338 if (error) 339 goto bad; 340 } 341 342 if ((error = trace_enter(code, callp, args)) != 0) 343 goto out; 344 345 rval[0] = 0; 346 rval[1] = frame->f_regs[D1]; 347 error = sy_call(callp, l, args, rval); 348 out: 349 switch (error) { 350 case 0: 351 /* 352 * Reinitialize lwp/proc pointers as they may be different 353 * if this is a child returning from fork syscall. 354 */ 355 l = curlwp; 356 p = l->l_proc; 357 frame->f_regs[D0] = rval[0]; 358 frame->f_regs[D1] = rval[1]; 359 frame->f_sr &= ~PSL_C; /* carry bit */ 360 #ifdef COMPAT_50 361 /* see syscall_plain for a comment explaining this */ 362 363 /* 364 * Some pre-m68k ELF libc assembler stubs assume 365 * %a0 is preserved across system calls... 366 */ 367 if (p->p_emul == &emul_netbsd) 368 frame->f_regs[A0] = rval[0]; 369 #endif 370 break; 371 case ERESTART: 372 /* 373 * We always enter through a `trap' instruction, which is 2 374 * bytes, so adjust the pc by that amount. 375 */ 376 frame->f_pc = frame->f_pc - 2; 377 break; 378 case EJUSTRETURN: 379 /* nothing to do */ 380 break; 381 default: 382 bad: 383 /* 384 * XXX: SVR4 uses this code-path, so we may have 385 * to translate errno. 386 */ 387 if (p->p_emul->e_errno) 388 error = p->p_emul->e_errno[error]; 389 frame->f_regs[D0] = error; 390 frame->f_sr |= PSL_C; /* carry bit */ 391 break; 392 } 393 394 trace_exit(code, callp, args, rval, error); 395 } 396 397 void 398 md_child_return(struct lwp *l) 399 { 400 /* See cpu_lwp_fork() */ 401 struct frame *f = (struct frame *)l->l_md.md_regs; 402 403 f->f_regs[D0] = 0; 404 f->f_sr &= ~PSL_C; 405 f->f_format = FMT0; 406 407 userret(l, f, 0); 408 } 409 410 /* 411 * Start a new LWP 412 */ 413 void 414 startlwp(void *arg) 415 { 416 ucontext_t *uc = arg; 417 lwp_t *l = curlwp; 418 struct frame *f = (struct frame *)l->l_md.md_regs; 419 int error __diagused; 420 421 f->f_regs[D0] = 0; 422 f->f_sr &= ~PSL_C; 423 f->f_format = FMT0; 424 425 error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags); 426 KASSERT(error == 0); 427 428 kmem_free(uc, sizeof(ucontext_t)); 429 userret(l, f, 0); 430 } 431 432 /* 433 * Process the tail end of a posix_spawn() for the child. 434 */ 435 void 436 cpu_spawn_return(struct lwp *l) 437 { 438 struct frame *f = (struct frame *)l->l_md.md_regs; 439 440 userret(l, f, 0); 441 } 442