2 * Copyright (c) 2010 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <ahornung@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include "opt_compat.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/imgact.h>
40 #include <sys/imgact_aout.h>
41 #include <sys/imgact_elf.h>
42 #include <sys/kern_syscall.h>
44 #include <sys/mplock2.h>
45 #include <sys/malloc.h>
46 #include <sys/ptrace.h>
48 #include <sys/signalvar.h>
49 #include <sys/sysent.h>
50 #include <sys/sysproto.h>
53 #include <vm/vm_param.h>
54 #include <vm/vm_page.h>
55 #include <vm/vm_extern.h>
57 #include <sys/kernel.h>
58 #include <sys/module.h>
59 #include <machine/cpu.h>
61 #include "i386/linux.h"
62 #include "i386/linux_proto.h"
63 #include "linux_signal.h"
64 #include "linux_util.h"
65 #include "linux_emuldata.h"
68 struct lock emul_lock
;
70 struct linux_emuldata
*
71 emuldata_get(struct proc
*p
)
73 struct linux_emuldata
*em
;
84 emuldata_set_robust(struct proc
*p
, struct linux_robust_list_head
*robust_ftx
)
86 struct linux_emuldata
*em
;
93 em
->robust_futexes
= robust_ftx
;
98 emuldata_init(struct proc
*p
, struct proc
*pchild
, int flags
)
100 struct linux_emuldata_shared
*s
;
101 struct linux_emuldata
*em
, *ep
;
106 em
= emuldata_get(p
);
108 if (pchild
== NULL
) {
110 /* This is the execv* case, where a process gets overwritten */
111 KKASSERT(em
!= NULL
);
112 KKASSERT(em
->s
!= NULL
);
113 if (atomic_fetchadd_int(&em
->s
->refs
, -1) == 1) {
114 kfree(em
->s
, M_LINUX
);
118 KKASSERT(em
->s
->refs
>= 0);
120 em
->parent_tidptr
= NULL
;
121 em
->child_tidptr
= NULL
;
123 em
->clear_tid
= NULL
;
128 em
= kmalloc(sizeof(*em
), M_LINUX
, M_WAITOK
| M_ZERO
);
131 if (flags
& LINUX_CLONE_THREAD
) {
133 * If CLONE_THREAD is set, the child is placed in the same
134 * thread group as the calling process.
136 KKASSERT(ep
!= NULL
);
140 /* new thread group */
141 s
= kmalloc(sizeof(*s
), M_LINUX
, M_WAITOK
| M_ZERO
);
142 LIST_INIT(&s
->threads
);
144 s
->group_pid
= pchild
->p_pid
;
146 s
->group_pid
= p
->p_pid
;
150 em
->parent_tidptr
= ep
->parent_tidptr
;
151 em
->child_tidptr
= ep
->child_tidptr
;
153 em
->clone_flags
= ep
->clone_flags
;
157 em
->clone_flags
= flags
;
159 atomic_add_int(&s
->refs
, 1);
160 KKASSERT(s
->refs
>= 0);
162 LIST_INSERT_HEAD(&s
->threads
, em
, threads
);
165 if (pchild
!= NULL
) {
167 pchild
->p_emuldata
= em
;
174 /* emuldata_exit is modelled after NetBSD's */
176 emuldata_exit(void *unused
, struct proc
*p
)
178 struct linux_sys_futex_args cup
;
179 struct linux_emuldata
*em
;
182 if (__predict_true(p
->p_sysent
!= &elf_linux_sysvec
))
188 em
= emuldata_get(p
);
195 * Members of the thread groups others than the leader should
196 * exit quietely: no zombie stage, no signal. We do that by
197 * reparenting to init. init will collect us and nobody will
198 * notice what happened.
200 if ((em
->s
->group_pid
!= p
->p_pid
) &&
201 (em
->clone_flags
& LINUX_CLONE_THREAD
)) {
202 p
->p_sigparent
= SIGCHLD
;
204 wakeup((caddr_t
) initproc
); /* kern_exit seems to do this */
205 proc_reparent(p
, initproc
); /* XXX: might be dangerous */
208 if (em
->clear_tid
!= NULL
) {
210 copyout(&tid
, em
->clear_tid
, sizeof(tid
));
211 cup
.uaddr
= em
->clear_tid
;
212 cup
.op
= LINUX_FUTEX_WAKE
;
213 cup
.val
= 0x7fffffff; /* Awake everyone */
217 error
= sys_linux_sys_futex(&cup
);
219 kprintf("emuldata_exit futex stuff failed miserably\n");
222 LIST_REMOVE(em
, threads
);
224 p
->p_emuldata
= NULL
;
226 if ((em
->s
->group_pid
== p
->p_pid
) &&
227 (em
->s
->flags
& LINUX_LES_INEXITGROUP
)) {
228 p
->p_xstat
= em
->s
->xstat
;
231 if (atomic_fetchadd_int(&em
->s
->refs
, -1) == 1) {
232 kfree(em
->s
, M_LINUX
);
236 KKASSERT(em
->s
->refs
>= 0);
243 linux_proc_transition(void *unused
, struct image_params
*imgp
)
248 if (__predict_false(imgp
->proc
->p_sysent
== &elf_linux_sysvec
&&
249 imgp
->proc
->p_emuldata
== NULL
)) {
251 kprintf("timidly hello from proc_transition\n");
253 emuldata_init(p
, p
, 0);
258 linux_proc_userret(void)
260 struct proc
*p
= curproc
;
261 struct linux_emuldata
*em
;
263 em
= emuldata_get(p
);
264 KKASSERT(em
!= NULL
);
266 if (em
->clone_flags
& LINUX_CLONE_CHILD_SETTID
) {
267 copyout(&p
->p_pid
, (int *)em
->child_tidptr
,
275 linux_proc_fork(struct proc
*p
, struct proc
*parent
, void *child_tidptr
)
277 struct linux_emuldata
*em
;
279 em
= emuldata_get(p
);
280 KKASSERT(em
!= NULL
);
282 if (child_tidptr
!= NULL
)
283 em
->child_tidptr
= child_tidptr
;
285 /* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */
286 if (em
->clone_flags
& LINUX_CLONE_CHILD_CLEARTID
)
287 em
->clear_tid
= em
->child_tidptr
;
289 if (em
->clone_flags
& LINUX_CLONE_CHILD_SETTID
)
290 p
->p_userret
= linux_proc_userret
;
296 sys_linux_set_tid_address(struct linux_set_tid_address_args
*args
)
298 struct linux_emuldata
*em
;
302 em
= emuldata_get(curproc
);
303 KKASSERT(em
!= NULL
);
305 em
->clear_tid
= args
->tidptr
;
306 args
->sysmsg_iresult
= curproc
->p_pid
;