Home | History | Annotate | Line # | Download | only in amd64
      1 /*	$NetBSD: linux32_syscall.c,v 1.33 2023/10/05 19:41:03 ad Exp $ */
      2 
      3 #include <sys/cdefs.h>
      4 __KERNEL_RCSID(0, "$NetBSD: linux32_syscall.c,v 1.33 2023/10/05 19:41:03 ad Exp $");
      5 
      6 #include <sys/param.h>
      7 #include <sys/systm.h>
      8 #include <sys/proc.h>
      9 #include <sys/signal.h>
     10 #include <sys/syscall.h>
     11 #include <sys/syscallvar.h>
     12 
     13 #include <machine/cpu.h>
     14 #include <machine/psl.h>
     15 #include <machine/userret.h>
     16 
     17 #include <compat/linux32/linux32_syscall.h>
     18 #include <compat/linux32/common/linux32_errno.h>
     19 
     20 void linux32_syscall_intern(struct proc *);
     21 void linux32_syscall(struct trapframe *);
     22 
     23 void
     24 linux32_syscall_intern(struct proc *p)
     25 {
     26 
     27 	p->p_md.md_syscall = linux32_syscall;
     28 }
     29 
     30 void
     31 linux32_syscall(struct trapframe *frame)
     32 {
     33 	const struct sysent *callp;
     34 	struct proc *p;
     35 	struct lwp *l;
     36 	int error;
     37 	size_t narg;
     38 	register32_t code, args[6];
     39 	register_t rval[2];
     40 	int i;
     41 	register_t args64[6];
     42 
     43 	l = curlwp;
     44 	p = l->l_proc;
     45 
     46 	code = frame->tf_rax;
     47 
     48 	callp = p->p_emul->e_sysent;
     49 
     50 	code &= (LINUX32_SYS_NSYSENT - 1);
     51 	callp += code;
     52 
     53 	/*
     54 	 * Linux passes the args in ebx, ecx, edx, esi, edi, ebp, in
     55 	 * increasing order.
     56 	 */
     57 	args[0] = frame->tf_rbx & 0xffffffff;
     58 	args[1] = frame->tf_rcx & 0xffffffff;
     59 	args[2] = frame->tf_rdx & 0xffffffff;
     60 	args[3] = frame->tf_rsi & 0xffffffff;
     61 	args[4] = frame->tf_rdi & 0xffffffff;
     62 	args[5] = frame->tf_rbp & 0xffffffff;
     63 
     64 	if (__predict_false(p->p_trace_enabled || KDTRACE_ENTRY(callp->sy_return))) {
     65 		narg = callp->sy_narg;
     66 		if (__predict_false(narg > __arraycount(args)))
     67 			panic("impossible syscall narg, code %d, narg %zu",
     68 			    code, narg);
     69 		for (i = 0; i < narg; i++)
     70 			args64[i] = args[i] & 0xffffffff;
     71 		if ((error = trace_enter(code, callp, args64)) != 0)
     72 			goto out;
     73 	}
     74 
     75 	rval[0] = 0;
     76 	rval[1] = 0;
     77 
     78 	error = sy_call(callp, l, args, rval);
     79 out:
     80 	switch (error) {
     81 	case 0:
     82 		frame->tf_rax = rval[0];
     83 		frame->tf_rflags &= ~PSL_C;	/* carry bit */
     84 		break;
     85 	case ERESTART:
     86 		/*
     87 		 * The offset to adjust the PC by depends on whether we entered
     88 		 * the kernel through the trap or call gate.  We pushed the
     89 		 * size of the instruction into tf_err on entry.
     90 		 */
     91 		frame->tf_rip -= frame->tf_err;
     92 		break;
     93 	case EJUSTRETURN:
     94 		/* nothing to do */
     95 		break;
     96 	default:
     97 		error = native_to_linux32_errno[error];
     98 		frame->tf_rax = error;
     99 		frame->tf_rflags |= PSL_C;	/* carry bit */
    100 		break;
    101 	}
    102 
    103 	if (__predict_false(p->p_trace_enabled || KDTRACE_ENTRY(callp->sy_return))) {
    104 		narg = callp->sy_narg;
    105 		for (i = 0; i < narg; i++)
    106 			args64[i] = args[i] & 0xffffffff;
    107 		trace_exit(code, callp, args64, rval, error);
    108 	}
    109 	userret(l);
    110 }
    111