1/* $NetBSD: linux32_syscall.c,v 1.32 2015/03/07 18:41:40 christos Exp $ */
2
3#include <sys/cdefs.h>
4__KERNEL_RCSID(0, "$NetBSD: linux32_syscall.c,v 1.32 2015/03/07 18:41:40 christos 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
20void linux32_syscall_intern(struct proc *);
21void linux32_syscall(struct trapframe *);
22
23void
24linux32_syscall_intern(struct proc *p)
25{
26
27 p->p_md.md_syscall = linux32_syscall;
28}
29
30void
31linux32_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 LWP_CACHE_CREDS(l, p);
49
50 callp = p->p_emul->e_sysent;
51
52 code &= (LINUX32_SYS_NSYSENT - 1);
53 callp += code;
54
55 /*
56 * Linux passes the args in ebx, ecx, edx, esi, edi, ebp, in
57 * increasing order.
58 */
59 args[0] = frame->tf_rbx & 0xffffffff;
60 args[1] = frame->tf_rcx & 0xffffffff;
61 args[2] = frame->tf_rdx & 0xffffffff;
62 args[3] = frame->tf_rsi & 0xffffffff;
63 args[4] = frame->tf_rdi & 0xffffffff;
64 args[5] = frame->tf_rbp & 0xffffffff;
65
66 if (__predict_false(p->p_trace_enabled || KDTRACE_ENTRY(callp->sy_return))) {
67 narg = callp->sy_narg;
68 if (__predict_false(narg > __arraycount(args)))
69 panic("impossible syscall narg, code %d, narg %zu",
70 code, narg);
71 for (i = 0; i < narg; i++)
72 args64[i] = args[i] & 0xffffffff;
73 if ((error = trace_enter(code, callp, args64)) != 0)
74 goto out;
75 }
76
77 rval[0] = 0;
78 rval[1] = 0;
79
80 error = sy_call(callp, l, args, rval);
81out:
82 switch (error) {
83 case 0:
84 frame->tf_rax = rval[0];
85 frame->tf_rflags &= ~PSL_C; /* carry bit */
86 break;
87 case ERESTART:
88 /*
89 * The offset to adjust the PC by depends on whether we entered
90 * the kernel through the trap or call gate. We pushed the
91 * size of the instruction into tf_err on entry.
92 */
93 frame->tf_rip -= frame->tf_err;
94 break;
95 case EJUSTRETURN:
96 /* nothing to do */
97 break;
98 default:
99 error = native_to_linux32_errno[error];
100 frame->tf_rax = error;
101 frame->tf_rflags |= PSL_C; /* carry bit */
102 break;
103 }
104
105 if (__predict_false(p->p_trace_enabled || KDTRACE_ENTRY(callp->sy_return))) {
106 narg = callp->sy_narg;
107 for (i = 0; i < narg; i++)
108 args64[i] = args[i] & 0xffffffff;
109 trace_exit(code, callp, args64, rval, error);
110 }
111 userret(l);
112}
113