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