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