1 | /* $NetBSD: linux_exec.c,v 1.117 2014/11/09 17:48:08 maxv Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1994, 1995, 1998, 2000, 2007, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Christos Zoulas, Frank van der Linden, Eric Haszlakiewicz and |
9 | * Thor Lancelot Simon. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | |
33 | #include <sys/cdefs.h> |
34 | __KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.117 2014/11/09 17:48:08 maxv Exp $" ); |
35 | |
36 | #include <sys/param.h> |
37 | #include <sys/systm.h> |
38 | #include <sys/kernel.h> |
39 | #include <sys/proc.h> |
40 | #include <sys/namei.h> |
41 | #include <sys/vnode.h> |
42 | #include <sys/mount.h> |
43 | #include <sys/exec.h> |
44 | #include <sys/exec_elf.h> |
45 | |
46 | #include <sys/mman.h> |
47 | #include <sys/syscallargs.h> |
48 | |
49 | #include <sys/ptrace.h> /* For proc_reparent() */ |
50 | |
51 | #include <uvm/uvm_extern.h> |
52 | |
53 | #include <sys/cpu.h> |
54 | #include <machine/reg.h> |
55 | |
56 | #include <compat/linux/common/linux_types.h> |
57 | #include <compat/linux/common/linux_signal.h> |
58 | #include <compat/linux/common/linux_util.h> |
59 | #include <compat/linux/common/linux_sched.h> |
60 | #include <compat/linux/common/linux_machdep.h> |
61 | #include <compat/linux/common/linux_exec.h> |
62 | #include <compat/linux/common/linux_futex.h> |
63 | #include <compat/linux/common/linux_ipc.h> |
64 | #include <compat/linux/common/linux_sem.h> |
65 | |
66 | #include <compat/linux/linux_syscallargs.h> |
67 | #include <compat/linux/linux_syscall.h> |
68 | #include <compat/linux/common/linux_misc.h> |
69 | #include <compat/linux/common/linux_errno.h> |
70 | #include <compat/linux/common/linux_emuldata.h> |
71 | |
72 | extern struct sysent linux_sysent[]; |
73 | extern const char * const linux_syscallnames[]; |
74 | extern char linux_sigcode[], linux_esigcode[]; |
75 | |
76 | /* |
77 | * Emulation switch. |
78 | */ |
79 | |
80 | struct uvm_object *emul_linux_object; |
81 | |
82 | struct emul emul_linux = { |
83 | .e_name = "linux" , |
84 | .e_path = "/emul/linux" , |
85 | #ifndef __HAVE_MINIMAL_EMUL |
86 | .e_flags = 0, |
87 | .e_errno = native_to_linux_errno, |
88 | .e_nosys = LINUX_SYS_syscall, |
89 | .e_nsysent = LINUX_SYS_NSYSENT, |
90 | #endif |
91 | .e_sysent = linux_sysent, |
92 | .e_syscallnames = linux_syscallnames, |
93 | .e_sendsig = linux_sendsig, |
94 | .e_trapsignal = linux_trapsignal, |
95 | .e_tracesig = NULL, |
96 | .e_sigcode = linux_sigcode, |
97 | .e_esigcode = linux_esigcode, |
98 | .e_sigobject = &emul_linux_object, |
99 | .e_setregs = linux_setregs, |
100 | .e_proc_exec = linux_e_proc_exec, |
101 | .e_proc_fork = linux_e_proc_fork, |
102 | .e_proc_exit = linux_e_proc_exit, |
103 | .e_lwp_fork = linux_e_lwp_fork, |
104 | .e_lwp_exit = linux_e_lwp_exit, |
105 | #ifdef __HAVE_SYSCALL_INTERN |
106 | .e_syscall_intern = linux_syscall_intern, |
107 | #else |
108 | #error Implement __HAVE_SYSCALL_INTERN for this platform |
109 | #endif |
110 | .e_sysctlovly = NULL, |
111 | .e_fault = NULL, |
112 | .e_vm_default_addr = uvm_default_mapaddr, |
113 | .e_usertrap = linux_usertrap, |
114 | .e_ucsize = 0, |
115 | .e_startlwp = NULL |
116 | }; |
117 | |
118 | void |
119 | linux_e_proc_exec(struct proc *p, struct exec_package *epp) |
120 | { |
121 | struct lwp *l; |
122 | |
123 | l = LIST_FIRST(&p->p_lwps); |
124 | if (l->l_emuldata == NULL) { |
125 | l->l_emuldata = kmem_zalloc(sizeof(struct linux_emuldata), KM_SLEEP); |
126 | } else { |
127 | memset(l->l_emuldata, 0, sizeof (struct linux_emuldata)); |
128 | } |
129 | |
130 | KASSERT(p->p_nlwps == 1); |
131 | l = LIST_FIRST(&p->p_lwps); |
132 | mutex_enter(p->p_lock); |
133 | l->l_lid = p->p_pid; |
134 | mutex_exit(p->p_lock); |
135 | } |
136 | |
137 | void |
138 | linux_e_proc_exit(struct proc *p) |
139 | { |
140 | struct lwp *l; |
141 | |
142 | KASSERT(p->p_nlwps == 1); |
143 | l = LIST_FIRST(&p->p_lwps); |
144 | linux_e_lwp_exit(l); |
145 | } |
146 | |
147 | void |
148 | linux_e_proc_fork(struct proc *p2, struct lwp *l1, int flags) |
149 | { |
150 | struct linux_emuldata *led1, *led2; |
151 | struct lwp *l2; |
152 | |
153 | KASSERT(p2->p_nlwps == 1); |
154 | l2 = LIST_FIRST(&p2->p_lwps); |
155 | l2->l_lid = p2->p_pid; |
156 | led1 = l1->l_emuldata; |
157 | led2 = l2->l_emuldata; |
158 | led2->led_child_tidptr = led1->led_child_tidptr; |
159 | } |
160 | |
161 | void |
162 | linux_e_lwp_fork(struct lwp *l1, struct lwp *l2) |
163 | { |
164 | struct linux_emuldata *led2; |
165 | |
166 | led2 = kmem_zalloc(sizeof(*led2), KM_SLEEP); |
167 | l2->l_emuldata = led2; |
168 | } |
169 | |
170 | void |
171 | linux_e_lwp_exit(struct lwp *l) |
172 | { |
173 | struct linux_emuldata *led; |
174 | struct linux_sys_futex_args cup; |
175 | register_t retval; |
176 | int error, zero = 0; |
177 | |
178 | led = l->l_emuldata; |
179 | if (led->led_clear_tid == NULL) { |
180 | return; |
181 | } |
182 | |
183 | /* Emulate LINUX_CLONE_CHILD_CLEARTID */ |
184 | error = copyout(&zero, led->led_clear_tid, sizeof(zero)); |
185 | #ifdef DEBUG_LINUX |
186 | if (error != 0) |
187 | printf("%s: cannot clear TID\n" , __func__); |
188 | #endif |
189 | |
190 | SCARG(&cup, uaddr) = led->led_clear_tid; |
191 | SCARG(&cup, op) = LINUX_FUTEX_WAKE; |
192 | SCARG(&cup, val) = 0x7fffffff; /* Awake everyone */ |
193 | SCARG(&cup, timeout) = NULL; |
194 | SCARG(&cup, uaddr2) = NULL; |
195 | SCARG(&cup, val3) = 0; |
196 | if ((error = linux_sys_futex(curlwp, &cup, &retval)) != 0) |
197 | printf("%s: linux_sys_futex failed\n" , __func__); |
198 | |
199 | release_futexes(l); |
200 | |
201 | led = l->l_emuldata; |
202 | l->l_emuldata = NULL; |
203 | kmem_free(led, sizeof(*led)); |
204 | } |
205 | |