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 | |
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 | 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); |
81 | out: |
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 | |