xref: /netbsd-src/sys/arch/amd64/amd64/linux32_syscall.c (revision 68fa58437753598de948829082f591c269b48777)
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
linux32_syscall_intern(struct proc * p)24 linux32_syscall_intern(struct proc *p)
25 {
26 
27 	p->p_md.md_syscall = linux32_syscall;
28 }
29 
30 void
linux32_syscall(struct trapframe * frame)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