sbin/hammer: Directly access volume in volume list
[dragonfly.git] / sys / emulation / linux / linux_emuldata.c
blob79cb1805eaed8175f384e603904c7eea57a5799e
1 /*
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
9 * are met:
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
16 * distribution.
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
32 * SUCH DAMAGE.
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>
43 #include <sys/lock.h>
44 #include <sys/mplock2.h>
45 #include <sys/malloc.h>
46 #include <sys/ptrace.h>
47 #include <sys/proc.h>
48 #include <sys/signalvar.h>
49 #include <sys/sysent.h>
50 #include <sys/sysproto.h>
52 #include <vm/vm.h>
53 #include <vm/vm_param.h>
54 #include <vm/vm_page.h>
55 #include <vm/vm_extern.h>
56 #include <sys/exec.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;
75 EMUL_LOCK();
77 em = p->p_emuldata;
79 EMUL_UNLOCK();
80 return (em);
83 void
84 emuldata_set_robust(struct proc *p, struct linux_robust_list_head *robust_ftx)
86 struct linux_emuldata *em;
88 EMUL_LOCK();
90 em = emuldata_get(p);
91 KKASSERT(em != NULL);
93 em->robust_futexes = robust_ftx;
94 EMUL_UNLOCK();
97 int
98 emuldata_init(struct proc *p, struct proc *pchild, int flags)
100 struct linux_emuldata_shared *s;
101 struct linux_emuldata *em, *ep;
102 int error = 0;
104 EMUL_LOCK();
106 em = emuldata_get(p);
108 if (pchild == NULL) {
109 ep = 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);
115 em->s = NULL;
117 if (em->s)
118 KKASSERT(em->s->refs >= 0);
120 em->parent_tidptr = NULL;
121 em->child_tidptr = NULL;
122 em->clone_flags = 0;
123 em->clear_tid = NULL;
124 em->set_tls = NULL;
125 em->proc = p;
126 } else {
127 ep = em;
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);
137 em->s = ep->s;
138 s = em->s;
139 } else {
140 /* new thread group */
141 s = kmalloc(sizeof(*s), M_LINUX, M_WAITOK | M_ZERO);
142 LIST_INIT(&s->threads);
143 if (pchild)
144 s->group_pid = pchild->p_pid;
145 else
146 s->group_pid = p->p_pid;
149 if (ep != NULL) {
150 em->parent_tidptr = ep->parent_tidptr;
151 em->child_tidptr = ep->child_tidptr;
152 #if 0
153 em->clone_flags = ep->clone_flags;
154 #endif
157 em->clone_flags = flags;
159 atomic_add_int(&s->refs, 1);
160 KKASSERT(s->refs >= 0);
161 em->s = s;
162 LIST_INSERT_HEAD(&s->threads, em, threads);
165 if (pchild != NULL) {
166 em->proc = pchild;
167 pchild->p_emuldata = em;
170 EMUL_UNLOCK();
171 return (error);
174 /* emuldata_exit is modelled after NetBSD's */
175 void
176 emuldata_exit(void *unused, struct proc *p)
178 struct linux_sys_futex_args cup;
179 struct linux_emuldata *em;
180 int error = 0;
182 if (__predict_true(p->p_sysent != &elf_linux_sysvec))
183 return;
185 release_futexes(p);
186 EMUL_LOCK();
188 em = emuldata_get(p);
189 if (em == NULL) {
190 EMUL_UNLOCK();
191 return;
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);
218 em->s = NULL;
220 if (em->s)
221 KKASSERT(em->s->refs >= 0);
223 EMUL_UNLOCK();
225 if (em->clear_tid != NULL) {
226 int tid = 0;
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 */
231 cup.timeout = NULL;
232 cup.uaddr2 = NULL;
233 cup.val3 = 0;
234 error = sys_linux_sys_futex(&cup);
235 if (error)
236 kprintf("emuldata_exit futex stuff failed miserably\n");
239 kfree(em, M_LINUX);
242 void
243 linux_proc_transition(void *unused, struct image_params *imgp)
245 struct proc *p;
247 p = imgp->proc;
248 if (__predict_false(imgp->proc->p_sysent == &elf_linux_sysvec &&
249 imgp->proc->p_emuldata == NULL)) {
250 #ifdef LINUX_DEBUG
251 kprintf("timidly hello from proc_transition\n");
252 #endif
253 emuldata_init(p, p, 0);
257 static void
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,
268 sizeof(p->p_pid));
271 return;
274 void
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;
292 return;
296 sys_linux_set_tid_address(struct linux_set_tid_address_args *args)
298 struct linux_emuldata *em;
300 EMUL_LOCK();
302 em = emuldata_get(curproc);
303 KKASSERT(em != NULL);
305 em->clear_tid = args->tidptr;
306 args->sysmsg_iresult = curproc->p_pid;
308 EMUL_UNLOCK();
309 return 0;