1 /* $NetBSD: darwin_exec.c,v 1.55.4.2 2009/04/01 00:27:20 snj Exp $ */
2
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 *
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.
30 */
31
32 #include "opt_compat_darwin.h" /* For COMPAT_DARWIN in mach_port.h */
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: darwin_exec.c,v 1.55.4.2 2009/04/01 00:27:20 snj Exp $");
35
36 #include "opt_syscall_debug.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/proc.h>
41 #include <sys/exec.h>
42 #include <sys/malloc.h>
43 #include <sys/syscall.h>
44 #include <sys/sysctl.h>
45 #include <sys/conf.h>
46 #include <sys/exec_macho.h>
47
48 #include <uvm/uvm_extern.h>
49 #include <uvm/uvm_param.h>
50
51 #include <dev/wscons/wsconsio.h>
52
53 #include <compat/sys/signal.h>
54
55 #include <compat/common/compat_util.h>
56
57 #include <compat/mach/mach_types.h>
58 #include <compat/mach/mach_message.h>
59 #include <compat/mach/mach_exec.h>
60 #include <compat/mach/mach_port.h>
61
62 #include <compat/darwin/darwin_exec.h>
63 #include <compat/darwin/darwin_commpage.h>
64 #include <compat/darwin/darwin_signal.h>
65 #include <compat/darwin/darwin_syscall.h>
66 #include <compat/darwin/darwin_sysctl.h>
67 #include <compat/darwin/darwin_iokit.h>
68 #include <compat/darwin/darwin_iohidsystem.h>
69
70 #include <machine/darwin_machdep.h>
71
72 /* Redefined from sys/dev/wscons/wsdisplay.c */
73 extern const struct cdevsw wsdisplay_cdevsw;
74
75 static void darwin_e_proc_exec(struct proc *, struct exec_package *);
76 static void darwin_e_proc_fork(struct proc *, struct proc *, int);
77 static void darwin_e_proc_exit(struct proc *);
78 static void darwin_e_proc_init(struct proc *, struct vmspace *);
79
80 extern struct sysent darwin_sysent[];
81 #ifdef SYSCALL_DEBUG
82 extern const char * const darwin_syscallnames[];
83 #endif
84 #ifndef __HAVE_SYSCALL_INTERN
85 void syscall(void);
86 #else
87 void mach_syscall_intern(struct proc *);
88 #endif
89
90 const struct emul emul_darwin = {
91 "darwin",
92 "/emul/darwin",
93 #ifndef __HAVE_MINIMAL_EMUL
94 0,
95 0,
96 DARWIN_SYS_syscall,
97 DARWIN_SYS_NSYSENT,
98 #endif
99 darwin_sysent,
100 #ifdef SYSCALL_DEBUG
101 darwin_syscallnames,
102 #else
103 NULL,
104 #endif
105 darwin_sendsig,
106 darwin_trapsignal,
107 darwin_tracesig,
108 NULL,
109 NULL,
110 NULL,
111 setregs,
112 darwin_e_proc_exec,
113 darwin_e_proc_fork,
114 darwin_e_proc_exit,
115 mach_e_lwp_fork,
116 mach_e_lwp_exit,
117 #ifdef __HAVE_SYSCALL_INTERN
118 mach_syscall_intern,
119 #else
120 syscall,
121 #endif
122 NULL,
123 NULL,
124
125 uvm_default_mapaddr,
126 NULL,
127 NULL,
128 0,
129 NULL,
130 };
131
132 /*
133 * Copy arguments onto the stack in the normal way, but add some
134 * extra information in case of dynamic binding.
135 */
136 int
137 exec_darwin_copyargs(struct lwp *l, struct exec_package *pack, struct ps_strings *arginfo, char **stackp, void *argp)
138 {
139 struct exec_macho_emul_arg *emea;
140 struct exec_macho_object_header *macho_hdr;
141 struct proc *p = l->l_proc;
142 char **cpp, *dp, *sp, *progname;
143 size_t len;
144 void *nullp = NULL;
145 long argc, envc;
146 int error;
147
148 /*
149 * Prepare the comm pages
150 */
151 if ((error = darwin_commpage_map(p)) != 0)
152 return error;
153
154 /*
155 * Set up the stack
156 */
157 *stackp = (char *)(((unsigned long)*stackp - 1) & ~0xfUL);
158
159 emea = (struct exec_macho_emul_arg *)pack->ep_emul_arg;
160
161 if (emea->dynamic == 1) {
162 macho_hdr = (struct exec_macho_object_header *)emea->macho_hdr;
163 error = copyout(&macho_hdr, *stackp, sizeof(macho_hdr));
164 if (error != 0)
165 return error;
166 *stackp += sizeof(macho_hdr);
167 }
168
169 cpp = (char **)*stackp;
170 argc = arginfo->ps_nargvstr;
171 envc = arginfo->ps_nenvstr;
172 if ((error = copyout(&argc, cpp++, sizeof(argc))) != 0)
173 return error;
174
175 dp = (char *) (cpp + argc + envc + 4);
176
177 if ((error = copyoutstr(emea->filename, dp,
178 (ARG_MAX < MAXPATHLEN) ? ARG_MAX : MAXPATHLEN, &len)) != 0)
179 return error;
180 progname = dp;
181 dp += len;
182
183 sp = argp;
184 arginfo->ps_argvstr = cpp; /* remember location of argv for later */
185 for (; --argc >= 0; sp += len, dp += len)
186 if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 ||
187 (error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0)
188 return error;
189
190 if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
191 return error;
192
193 arginfo->ps_envstr = cpp; /* remember location of envp for later */
194 for (; --envc >= 0; sp += len, dp += len)
195 if ((error = copyout(&dp, cpp++, sizeof(dp))) != 0 ||
196 (error = copyoutstr(sp, dp, ARG_MAX, &len)) != 0)
197 return error;
198
199 if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
200 return error;
201
202 if ((error = copyout(&progname, cpp++, sizeof(progname))) != 0)
203 return error;
204
205 if ((error = copyout(&nullp, cpp++, sizeof(nullp))) != 0)
206 return error;
207
208 *stackp = (char *)cpp;
209
210 /* We don't need this anymore */
211 free(pack->ep_emul_arg, M_TEMP);
212 pack->ep_emul_arg = NULL;
213
214 return 0;
215 }
216
217 int
218 exec_darwin_probe(const char **path)
219 {
220 *path = emul_darwin.e_path;
221 return 0;
222 }
223
224 static void
225 darwin_e_proc_exec(struct proc *p, struct exec_package *epp)
226 {
227 struct darwin_emuldata *ded;
228
229 darwin_e_proc_init(p, p->p_vmspace);
230
231 /* Setup the mach_emuldata part of darwin_emuldata */
232 mach_e_proc_exec(p, epp);
233
234 ded = (struct darwin_emuldata *)p->p_emuldata;
235 if (p->p_pid == darwin_init_pid)
236 ded->ded_fakepid = 1;
237 #ifdef DEBUG_DARWIN
238 printf("pid %d exec'd: fakepid = %d\n", p->p_pid, ded->ded_fakepid);
239 #endif
240
241 return;
242 }
243
244 static void
245 darwin_e_proc_fork(struct proc *p, struct proc *parent, int forkflags)
246 {
247 struct darwin_emuldata *ded1;
248 struct darwin_emuldata *ded2;
249 char *ed1, *ed2;
250 size_t len;
251
252 p->p_emuldata = NULL;
253
254 /* Use parent's vmspace because our vmspace may not be setup yet */
255 darwin_e_proc_init(p, parent->p_vmspace);
256
257 /*
258 * Setup the mach_emuldata part of darwin_emuldata
259 * The null third argument asks to not re-allocate
260 * p->p_emuldata again.
261 */
262 mach_e_proc_fork1(p, parent, 0);
263
264 ded1 = p->p_emuldata;
265 ded2 = parent->p_emuldata;
266
267 ed1 = (char *)ded1 + sizeof(struct mach_emuldata);;
268 ed2 = (char *)ded2 + sizeof(struct mach_emuldata);;
269 len = sizeof(struct darwin_emuldata) - sizeof(struct mach_emuldata);
270
271 (void)memcpy(ed1, ed2, len);
272
273 if ((ded2->ded_fakepid == 1) && (darwin_init_pid != 0)) {
274 darwin_init_pid = 0;
275 ded1->ded_fakepid = 2;
276 } else {
277 ded1->ded_fakepid = 0;
278 }
279 #ifdef DEBUG_DARWIN
280 printf("pid %d fork'd: fakepid = %d\n", p->p_pid, ded1->ded_fakepid);
281 #endif
282
283 return;
284 }
285
286 static void
287 darwin_e_proc_init(struct proc *p, struct vmspace *vmspace)
288 {
289 struct darwin_emuldata *ded;
290
291 if (!p->p_emuldata) {
292 p->p_emuldata = malloc(sizeof(struct darwin_emuldata),
293 M_EMULDATA, M_WAITOK | M_ZERO);
294
295 }
296 ded = (struct darwin_emuldata *)p->p_emuldata;
297 ded->ded_fakepid = 0;
298 ded->ded_wsdev = NODEV;
299 ded->ded_vramoffset = NULL;
300
301 /* Initalize the mach_emuldata part of darwin_emuldata */
302 mach_e_proc_init(p, vmspace);
303
304 return;
305 }
306
307 static void
308 darwin_e_proc_exit(struct proc *p)
309 {
310 struct darwin_emuldata *ded;
311 int error, mode;
312 struct lwp *l;
313
314 ded = p->p_emuldata;
315 l = LIST_FIRST(&p->p_lwps);
316 /*
317 * mach_init is setting the bootstrap port for other processes.
318 * If mach_init dies, we want to restore the original bootstrap
319 * port.
320 */
321 if (ded->ded_fakepid == 2)
322 mach_bootstrap_port = mach_saved_bootstrap_port;
323
324 /*
325 * Terminate the iohidsystem kernel thread.
326 * We need to post a fake event in case
327 * the thread is sleeping for an event.
328 */
329 if (ded->ded_hidsystem_finished != NULL) {
330 *ded->ded_hidsystem_finished = 1;
331 darwin_iohidsystem_postfake(l);
332 wakeup(ded->ded_hidsystem_finished);
333 }
334
335 /*
336 * Restore text mode and black and white colormap
337 */
338 if (ded->ded_wsdev != NODEV) {
339 mode = WSDISPLAYIO_MODE_EMUL;
340 error = (*wsdisplay_cdevsw.d_ioctl)(ded->ded_wsdev,
341 WSDISPLAYIO_SMODE, (void *)&mode, 0, l);
342 #ifdef DEBUG_DARWIN
343 if (error != 0)
344 printf("Unable to switch back to text mode\n");
345 #endif
346 #if 0 /* Comment out stackgap use - this needs to be done another way */
347 {
348 void *sg = stackgap_init(p, 0);
349 struct wsdisplay_cmap cmap;
350 u_char *red;
351 u_char *green;
352 u_char *blue;
353 u_char kred[256];
354 u_char kgreen[256];
355 u_char kblue[256];
356 red = stackgap_alloc(p, &sg, 256);
357 green = stackgap_alloc(p, &sg, 256);
358 blue = stackgap_alloc(p, &sg, 256);
359
360 (void)memset(kred, 255, 256);
361 (void)memset(kgreen, 255, 256);
362 (void)memset(kblue, 255, 256);
363
364 kred[0] = 0;
365 kgreen[0] = 0;
366 kblue[0] = 0;
367
368 cmap.index = 0;
369 cmap.count = 256;
370 cmap.red = red;
371 cmap.green = green;
372 cmap.blue = blue;
373
374 if (((error = copyout(kred, red, 256)) != 0) ||
375 ((error = copyout(kgreen, green, 256)) != 0) ||
376 ((error = copyout(kblue, blue, 256)) != 0))
377 error = (*wsdisplay_cdevsw.d_ioctl)(ded->ded_wsdev,
378 WSDISPLAYIO_PUTCMAP, (void *)&cmap, 0, l);
379 #ifdef DEBUG_DARWIN
380 if (error != 0)
381 printf("Cannot revert colormap (error %d)\n", error);
382 #endif
383 }
384 #endif
385
386 }
387
388 /*
389 * Cleanup mach_emuldata part of darwin_emuldata
390 * It will also free p->p_emuldata.
391 */
392 mach_e_proc_exit(p);
393
394 return;
395 }
396
397 int
398 darwin_exec_setup_stack(struct lwp *l, struct exec_package *epp)
399 {
400 u_long max_stack_size;
401 u_long access_linear_min, access_size;
402 u_long noaccess_linear_min, noaccess_size;
403
404 if (epp->ep_flags & EXEC_32) {
405 epp->ep_minsaddr = DARWIN_USRSTACK32;
406 max_stack_size = MAXSSIZ;
407 } else {
408 epp->ep_minsaddr = DARWIN_USRSTACK;
409 max_stack_size = MAXSSIZ;
410 }
411 epp->ep_maxsaddr = (u_long)STACK_GROW(epp->ep_minsaddr,
412 max_stack_size);
413 epp->ep_ssize = l->l_proc->p_rlimit[RLIMIT_STACK].rlim_cur;
414
415 /*
416 * set up commands for stack. note that this takes *two*, one to
417 * map the part of the stack which we can access, and one to map
418 * the part which we can't.
419 *
420 * arguably, it could be made into one, but that would require the
421 * addition of another mapping proc, which is unnecessary
422 */
423 access_size = epp->ep_ssize;
424 access_linear_min = (u_long)STACK_ALLOC(epp->ep_minsaddr, access_size);
425 noaccess_size = max_stack_size - access_size;
426 noaccess_linear_min = (u_long)STACK_ALLOC(STACK_GROW(epp->ep_minsaddr,
427 access_size), noaccess_size);
428 if (noaccess_size > 0) {
429 NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, noaccess_size,
430 noaccess_linear_min, NULL, 0, VM_PROT_NONE, VMCMD_STACK);
431 }
432 KASSERT(access_size > 0);
433 NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, access_size,
434 access_linear_min, NULL, 0, VM_PROT_READ | VM_PROT_WRITE,
435 VMCMD_STACK);
436
437 return 0;
438 }
Cache object: 686d14820de17637e9341a44e471f38e
|