1 /* $NetBSD: mach_exec.c,v 1.71 2008/11/19 18:36:05 ad Exp $ */
4 * Copyright (c) 2001-2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas and Emmanuel Dreyfus.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mach_exec.c,v 1.71 2008/11/19 18:36:05 ad Exp $");
35 #include "opt_syscall_debug.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
41 #include <sys/queue.h>
42 #include <sys/exec_macho.h>
43 #include <sys/malloc.h>
45 #include <sys/syscall.h>
46 #include <sys/syscallvar.h>
48 #include <uvm/uvm_extern.h>
49 #include <uvm/uvm_param.h>
51 #include <compat/mach/mach_types.h>
52 #include <compat/mach/mach_message.h>
53 #include <compat/mach/mach_port.h>
54 #include <compat/mach/mach_semaphore.h>
55 #include <compat/mach/mach_notify.h>
56 #include <compat/mach/mach_exec.h>
58 static int mach_cold
= 1; /* Have we initialized COMPAT_MACH structures? */
59 static void mach_init(void);
61 extern struct sysent sysent
[];
62 #ifndef __HAVE_SYSCALL_INTERN
65 void mach_syscall_intern(struct proc
*);
69 extern char sigcode
[], esigcode
[];
70 struct uvm_object
*emul_mach_object
;
73 struct emul emul_mach
= {
76 #ifndef __HAVE_MINIMAL_EMUL
106 #ifdef __HAVE_SYSCALL_INTERN
112 NULL
, /* e_vm_default_addr */
115 NULL
, /* e_usertrap */
118 NULL
, /* e_startlwp */
122 * Copy arguments onto the stack in the normal way, but add some
123 * extra information in case of dynamic binding.
124 * XXX This needs a cleanup: it is not used anymore by the Darwin
125 * emulation, and it probably contains Darwin specific bits.
128 exec_mach_copyargs(struct lwp
*l
, struct exec_package
*pack
, struct ps_strings
*arginfo
, char **stackp
, void *argp
)
130 struct exec_macho_emul_arg
*emea
;
131 struct exec_macho_object_header
*macho_hdr
;
136 *stackp
= (char *)(((unsigned long)*stackp
- 1) & ~0xfUL
);
138 emea
= (struct exec_macho_emul_arg
*)pack
->ep_emul_arg
;
139 macho_hdr
= (struct exec_macho_object_header
*)emea
->macho_hdr
;
140 if ((error
= copyout(&macho_hdr
, *stackp
, sizeof(macho_hdr
))) != 0)
143 *stackp
+= sizeof(macho_hdr
);
145 if ((error
= copyargs(l
, pack
, arginfo
, stackp
, argp
)) != 0) {
146 DPRINTF(("mach: copyargs failed\n"));
150 if ((error
= copyout(&zero
, *stackp
, sizeof(zero
))) != 0)
152 *stackp
+= sizeof(zero
);
154 if ((error
= copyoutstr(emea
->filename
,
155 *stackp
, MAXPATHLEN
, &len
)) != 0) {
156 DPRINTF(("mach: copyout path failed\n"));
161 /* We don't need this anymore */
162 free(pack
->ep_emul_arg
, M_TEMP
);
163 pack
->ep_emul_arg
= NULL
;
165 len
= len
% sizeof(zero
);
167 if ((error
= copyout(&zero
, *stackp
, len
)) != 0)
172 if ((error
= copyout(&zero
, *stackp
, sizeof(zero
))) != 0)
174 *stackp
+= sizeof(zero
);
180 exec_mach_probe(const char **path
)
182 *path
= emul_mach
.e_path
;
187 mach_e_proc_exec(struct proc
*p
, struct exec_package
*epp
)
189 mach_e_proc_init(p
, p
->p_vmspace
);
191 if (p
->p_emul
!= epp
->ep_esch
->es_emul
) {
192 struct lwp
*l
= LIST_FIRST(&p
->p_lwps
);
194 mach_e_lwp_fork(NULL
, l
);
201 mach_e_proc_fork(struct proc
*p
, struct proc
*parent
, int forkflags
)
203 mach_e_proc_fork1(p
, parent
, 1);
208 mach_e_proc_fork1(struct proc
*p
, struct proc
*parent
, int allocate
)
210 struct mach_emuldata
*med1
;
211 struct mach_emuldata
*med2
;
215 * For Darwin binaries, p->p_emuldata has already been
216 * allocated, no need to throw it away and allocate it again.
219 p
->p_emuldata
= NULL
;
221 /* Use parent's vmspace because our vmspace may not be set up yet */
222 mach_e_proc_init(p
, parent
->p_vmspace
);
224 med1
= p
->p_emuldata
;
225 med2
= parent
->p_emuldata
;
228 * Exception ports are inherited between forks,
229 * but we need to double their reference counts,
230 * since the ports are referenced by rights in the
231 * parent and in the child.
233 * XXX we need to convert all the parent's rights
234 * to the child namespace. This will make the
235 * following fixup obsolete.
237 for (i
= 0; i
<= MACH_EXC_MAX
; i
++) {
238 med1
->med_exc
[i
] = med2
->med_exc
[i
];
239 if (med1
->med_exc
[i
] != NULL
)
240 med1
->med_exc
[i
]->mp_refcount
*= 2;
247 mach_e_proc_init(struct proc
*p
, struct vmspace
*vmspace
)
249 struct mach_emuldata
*med
;
250 struct mach_right
*mr
;
253 * Initialize various things if needed.
254 * XXX Not the best place for this.
260 * For Darwin binaries, p->p_emuldata is always allocated:
261 * from the previous program if it had the same emulation,
262 * or from darwin_e_proc_exec(). In the latter situation,
263 * everything has been set to zero.
265 if (!p
->p_emuldata
) {
267 if (p
->p_emul
!= &emul_mach
)
268 printf("mach_emuldata allocated for non Mach binary\n");
270 p
->p_emuldata
= malloc(sizeof(struct mach_emuldata
),
271 M_EMULDATA
, M_WAITOK
| M_ZERO
);
274 med
= (struct mach_emuldata
*)p
->p_emuldata
;
277 * p->p_emudata has med_inited set if we inherited it from
278 * the program that called exec(). In that situation, we
279 * must free anything that will not be used anymore.
281 if (med
->med_inited
!= 0) {
282 rw_enter(&med
->med_rightlock
, RW_WRITER
);
283 while ((mr
= LIST_FIRST(&med
->med_right
)) != NULL
)
284 mach_right_put_exclocked(mr
, MACH_PORT_TYPE_ALL_RIGHTS
);
285 rw_exit(&med
->med_rightlock
);
288 * Do not touch special ports. Some other process (eg: gdb)
289 * might have grabbed them to control the process, and the
290 * controller intend to keep in control even after exec().
294 * p->p_emuldata is uninitialized. Go ahead and initialize it.
296 LIST_INIT(&med
->med_right
);
297 rw_init(&med
->med_rightlock
);
298 rw_init(&med
->med_exclock
);
301 * For debugging purpose, it's convenient to have each process
302 * using distinct port names, so we prefix the first port name
303 * by the PID. Darwin does not do that, but we can remove it
304 * when we want, it will not hurt.
306 med
->med_nextright
= p
->p_pid
<< 16;
309 * Initialize special ports. Bootstrap port is shared
310 * among all Mach processes in our implementation.
312 med
->med_kernel
= mach_port_get();
313 med
->med_host
= mach_port_get();
315 med
->med_kernel
->mp_flags
|= MACH_MP_INKERNEL
;
316 med
->med_host
->mp_flags
|= MACH_MP_INKERNEL
;
318 med
->med_kernel
->mp_data
= (void *)p
;
319 med
->med_host
->mp_data
= (void *)p
;
321 med
->med_kernel
->mp_datatype
= MACH_MP_PROC
;
322 med
->med_host
->mp_datatype
= MACH_MP_PROC
;
324 MACH_PORT_REF(med
->med_kernel
);
325 MACH_PORT_REF(med
->med_host
);
327 med
->med_bootstrap
= mach_bootstrap_port
;
328 MACH_PORT_REF(med
->med_bootstrap
);
332 * Exception ports are inherited accross exec() calls.
333 * If the structure is initialized, the ports are just
334 * here, so leave them untouched. If the structure is
335 * uninitalized, the ports are all set to zero, which
336 * is the default, so do not touch them either.
339 med
->med_dirty_thid
= 1;
340 med
->med_suspend
= 0;
347 mach_e_proc_exit(struct proc
*p
)
349 struct mach_emuldata
*med
;
350 struct mach_right
*mr
;
354 /* There is only one lwp remaining... */
355 l
= LIST_FIRST(&p
->p_lwps
);
359 med
= (struct mach_emuldata
*)p
->p_emuldata
;
361 rw_enter(&med
->med_rightlock
, RW_WRITER
);
362 while ((mr
= LIST_FIRST(&med
->med_right
)) != NULL
)
363 mach_right_put_exclocked(mr
, MACH_PORT_TYPE_ALL_RIGHTS
);
364 rw_exit(&med
->med_rightlock
);
366 MACH_PORT_UNREF(med
->med_bootstrap
);
369 * If the lock on this task exception handler is held,
370 * release it now as it will never be released by the
373 if (rw_lock_held(&med
->med_exclock
))
374 wakeup(&med
->med_exclock
);
377 * If the kernel and host port are still referenced, remove
378 * the pointer to this process' struct proc, as it will
379 * become invalid once the process will exit.
381 med
->med_kernel
->mp_datatype
= MACH_MP_NONE
;
382 med
->med_kernel
->mp_data
= NULL
;
383 MACH_PORT_UNREF(med
->med_kernel
);
385 med
->med_host
->mp_datatype
= MACH_MP_NONE
;
386 med
->med_host
->mp_data
= NULL
;
387 MACH_PORT_UNREF(med
->med_host
);
389 for (i
= 0; i
<= MACH_EXC_MAX
; i
++)
390 if (med
->med_exc
[i
] != NULL
)
391 MACH_PORT_UNREF(med
->med_exc
[i
]);
393 rw_destroy(&med
->med_exclock
);
394 rw_destroy(&med
->med_rightlock
);
395 free(med
, M_EMULDATA
);
396 p
->p_emuldata
= NULL
;
402 mach_e_lwp_fork(struct lwp
*l1
, struct lwp
*l2
)
404 struct mach_lwp_emuldata
*mle
;
406 mle
= malloc(sizeof(*mle
), M_EMULDATA
, M_WAITOK
);
407 l2
->l_emuldata
= mle
;
409 mle
->mle_kernel
= mach_port_get();
410 MACH_PORT_REF(mle
->mle_kernel
);
412 mle
->mle_kernel
->mp_flags
|= MACH_MP_INKERNEL
;
413 mle
->mle_kernel
->mp_datatype
= MACH_MP_LWP
;
414 mle
->mle_kernel
->mp_data
= (void *)l2
;
417 /* Nothing to copy from parent thread for now */
425 mach_e_lwp_exit(struct lwp
*l
)
427 struct mach_lwp_emuldata
*mle
;
429 mach_semaphore_cleanup(l
);
432 if (l
->l_emuldata
== NULL
) {
433 printf("lwp_emuldata already freed\n");
439 mle
->mle_kernel
->mp_data
= NULL
;
440 mle
->mle_kernel
->mp_datatype
= MACH_MP_NONE
;
441 MACH_PORT_UNREF(mle
->mle_kernel
);
443 free(mle
, M_EMULDATA
);
444 l
->l_emuldata
= NULL
;
452 mach_semaphore_init();