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);
194 LIST_REMOVE(em, threads);
195 p->p_emuldata = NULL;
198 * Members of the thread groups others than the leader should
199 * exit quietely: no zombie stage, no signal. We do that by
200 * reparenting to init. init will collect us and nobody will
201 * notice what happened.
203 if ((em->s->group_pid != p->p_pid) &&
204 (em->clone_flags & LINUX_CLONE_THREAD)) {
205 p->p_sigparent = SIGCHLD;
207 proc_reparent(p, initproc);
208 wakeup((caddr_t)initproc); /* kern_exit seems to do this */
211 if ((em->s->group_pid == p->p_pid) &&
212 (em->s->flags & LINUX_LES_INEXITGROUP)) {
213 p->p_xstat = em->s->xstat;
216 if (atomic_fetchadd_int(&em->s->refs, -1) == 1) {
217 kfree(em->s, M_LINUX);
221 KKASSERT(em->s->refs >= 0);
225 if (em->clear_tid != NULL) {
227 copyout(&tid, em->clear_tid, sizeof(tid));
228 cup.uaddr = em->clear_tid;
229 cup.op = LINUX_FUTEX_WAKE;
230 cup.val = 0x7fffffff; /* Awake everyone */
234 error = sys_linux_sys_futex(&cup);
236 kprintf("emuldata_exit futex stuff failed miserably\n");
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;