1 /* $NetBSD: linux_exec.c,v 1.83 2005/12/11 12:20:19 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1994, 1995, 1998, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas, Frank van der Linden, Eric Haszlakiewicz and 9 * Thor Lancelot Simon. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.83 2005/12/11 12:20:19 christos Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/proc.h> 47 #include <sys/malloc.h> 48 #include <sys/namei.h> 49 #include <sys/vnode.h> 50 #include <sys/mount.h> 51 #include <sys/exec.h> 52 #include <sys/exec_elf.h> 53 54 #include <sys/mman.h> 55 #include <sys/sa.h> 56 #include <sys/syscallargs.h> 57 58 #include <uvm/uvm_extern.h> 59 60 #include <machine/cpu.h> 61 #include <machine/reg.h> 62 63 #include <compat/linux/common/linux_types.h> 64 #include <compat/linux/common/linux_signal.h> 65 #include <compat/linux/common/linux_util.h> 66 #include <compat/linux/common/linux_exec.h> 67 #include <compat/linux/common/linux_machdep.h> 68 #include <compat/linux/common/linux_futex.h> 69 70 #include <compat/linux/linux_syscallargs.h> 71 #include <compat/linux/linux_syscall.h> 72 #include <compat/linux/common/linux_misc.h> 73 #include <compat/linux/common/linux_errno.h> 74 #include <compat/linux/common/linux_emuldata.h> 75 76 extern struct sysent linux_sysent[]; 77 extern const char * const linux_syscallnames[]; 78 extern char linux_sigcode[], linux_esigcode[]; 79 80 static void linux_e_proc_exec __P((struct proc *, struct exec_package *)); 81 static void linux_e_proc_fork __P((struct proc *, struct proc *, int)); 82 static void linux_e_proc_exit __P((struct proc *)); 83 static void linux_e_proc_init __P((struct proc *, struct proc *, int)); 84 85 #ifdef LINUX_NPTL 86 static void linux_userret __P((struct lwp *, void *)); 87 #endif 88 89 /* 90 * Execve(2). Just check the alternate emulation path, and pass it on 91 * to the NetBSD execve(). 92 */ 93 int 94 linux_sys_execve(l, v, retval) 95 struct lwp *l; 96 void *v; 97 register_t *retval; 98 { 99 struct linux_sys_execve_args /* { 100 syscallarg(const char *) path; 101 syscallarg(char **) argv; 102 syscallarg(char **) envp; 103 } */ *uap = v; 104 struct proc *p = l->l_proc; 105 struct sys_execve_args ap; 106 caddr_t sg; 107 108 sg = stackgap_init(p, 0); 109 CHECK_ALT_EXIST(l, &sg, SCARG(uap, path)); 110 111 SCARG(&ap, path) = SCARG(uap, path); 112 SCARG(&ap, argp) = SCARG(uap, argp); 113 SCARG(&ap, envp) = SCARG(uap, envp); 114 115 return sys_execve(l, &ap, retval); 116 } 117 118 /* 119 * Emulation switch. 120 */ 121 122 struct uvm_object *emul_linux_object; 123 124 const struct emul emul_linux = { 125 "linux", 126 "/emul/linux", 127 #ifndef __HAVE_MINIMAL_EMUL 128 0, 129 (const int *)native_to_linux_errno, 130 LINUX_SYS_syscall, 131 LINUX_SYS_NSYSENT, 132 #endif 133 linux_sysent, 134 linux_syscallnames, 135 linux_sendsig, 136 linux_trapsignal, 137 NULL, 138 linux_sigcode, 139 linux_esigcode, 140 &emul_linux_object, 141 linux_setregs, 142 linux_e_proc_exec, 143 linux_e_proc_fork, 144 linux_e_proc_exit, 145 NULL, 146 NULL, 147 #ifdef __HAVE_SYSCALL_INTERN 148 linux_syscall_intern, 149 #else 150 #error Implement __HAVE_SYSCALL_INTERN for this platform 151 #endif 152 NULL, 153 NULL, 154 155 uvm_default_mapaddr, 156 157 linux_usertrap, 158 }; 159 160 static void 161 linux_e_proc_init(p, parent, forkflags) 162 struct proc *p, *parent; 163 int forkflags; 164 { 165 struct linux_emuldata *e = p->p_emuldata; 166 struct linux_emuldata_shared *s; 167 struct linux_emuldata *ep = NULL; 168 169 if (!e) { 170 /* allocate new Linux emuldata */ 171 MALLOC(e, void *, sizeof(struct linux_emuldata), 172 M_EMULDATA, M_WAITOK); 173 } else { 174 e->s->refs--; 175 if (e->s->refs == 0) 176 FREE(e->s, M_EMULDATA); 177 } 178 179 memset(e, '\0', sizeof(struct linux_emuldata)); 180 181 if (parent) 182 ep = parent->p_emuldata; 183 184 if (forkflags & FORK_SHAREVM) { 185 #ifdef DIAGNOSTIC 186 if (ep == NULL) { 187 killproc(p, "FORK_SHAREVM while emuldata is NULL\n"); 188 return; 189 } 190 #endif 191 s = ep->s; 192 s->refs++; 193 } else { 194 struct vmspace *vm; 195 196 MALLOC(s, void *, sizeof(struct linux_emuldata_shared), 197 M_EMULDATA, M_WAITOK); 198 s->refs = 1; 199 200 /* 201 * Set the process idea of the break to the real value. 202 * For fork, we use parent's vmspace since our's 203 * is not setup at the time of this call and is going 204 * to be copy of parent's anyway. For exec, just 205 * use our own vmspace. 206 */ 207 vm = (parent) ? parent->p_vmspace : p->p_vmspace; 208 s->p_break = vm->vm_daddr + ctob(vm->vm_dsize); 209 210 /* 211 * Linux threads are emulated as NetBSD processes (not lwp) 212 * We use native PID for Linux TID. The Linux TID is the 213 * PID of the first process in the group. It is stored 214 * here 215 */ 216 s->group_pid = p->p_pid; 217 } 218 219 e->s = s; 220 221 #ifdef LINUX_NPTL 222 /* 223 * initialize TID pointers. ep->child_clear_tid and 224 * ep->child_set_tid will not be used beyond this point. 225 */ 226 e->child_clear_tid = NULL; 227 e->child_set_tid = NULL; 228 if (ep != NULL) { 229 e->clear_tid = ep->child_clear_tid; 230 e->set_tid = ep->child_set_tid; 231 e->set_tls = ep->set_tls; 232 ep->child_clear_tid = NULL; 233 ep->child_set_tid = NULL; 234 ep->set_tls = 0; 235 } else { 236 e->clear_tid = NULL; 237 e->set_tid = NULL; 238 e->set_tls = 0; 239 } 240 #endif /* LINUX_NPTL */ 241 242 p->p_emuldata = e; 243 } 244 245 /* 246 * Allocate new per-process structures. Called when executing Linux 247 * process. We can reuse the old emuldata - if it's not null, 248 * the executed process is of same emulation as original forked one. 249 */ 250 static void 251 linux_e_proc_exec(p, epp) 252 struct proc *p; 253 struct exec_package *epp; 254 { 255 /* exec, use our vmspace */ 256 linux_e_proc_init(p, NULL, 0); 257 } 258 259 /* 260 * Emulation per-process exit hook. 261 */ 262 static void 263 linux_e_proc_exit(p) 264 struct proc *p; 265 { 266 struct linux_emuldata *e = p->p_emuldata; 267 268 #ifdef LINUX_NPTL 269 /* Emulate LINUX_CLONE_CHILD_CLEARTID */ 270 if (e->clear_tid != NULL) { 271 int error; 272 int null = 0; 273 struct linux_sys_futex_args cup; 274 register_t retval; 275 struct lwp *l; 276 277 if ((error = copyout(&null, 278 e->clear_tid, 279 sizeof(null))) != 0) 280 printf("linux_e_proc_exit: cannot clear TID\n"); 281 282 l = proc_representative_lwp(p); 283 SCARG(&cup, uaddr) = e->clear_tid; 284 SCARG(&cup, op) = LINUX_FUTEX_WAKE; 285 SCARG(&cup, val) = 0x7fffffff; /* Awake everyone */ 286 SCARG(&cup, timeout) = NULL; 287 SCARG(&cup, uaddr2) = NULL; 288 SCARG(&cup, val3) = 0; 289 if ((error = linux_sys_futex(l, &cup, &retval)) != 0) 290 printf("linux_e_proc_exit: linux_sys_futex failed\n"); 291 } 292 #endif /* LINUX_NPTL */ 293 294 /* free Linux emuldata and set the pointer to null */ 295 e->s->refs--; 296 if (e->s->refs == 0) 297 FREE(e->s, M_EMULDATA); 298 FREE(e, M_EMULDATA); 299 p->p_emuldata = NULL; 300 } 301 302 /* 303 * Emulation fork hook. 304 */ 305 static void 306 linux_e_proc_fork(p, parent, forkflags) 307 struct proc *p, *parent; 308 int forkflags; 309 { 310 #ifdef LINUX_NPTL 311 struct linux_emuldata *e; 312 #endif 313 314 /* 315 * The new process might share some vmspace-related stuff 316 * with parent, depending on fork flags (CLONE_VM et.al). 317 * Force allocation of new base emuldata, and share the 318 * VM-related parts only if necessary. 319 */ 320 p->p_emuldata = NULL; 321 linux_e_proc_init(p, parent, forkflags); 322 323 #ifdef LINUX_NPTL 324 /* 325 * Emulate LINUX_CLONE_CHILD_SETTID and LINUX_CLONE_TLS: 326 * This cannot be done right now because the child VM 327 * is not set up. We will do it at userret time. 328 */ 329 e = p->p_emuldata; 330 if ((e->set_tid != NULL) || (e->set_tls != 0)) 331 p->p_userret = (*linux_userret); 332 #endif 333 334 return; 335 } 336 337 #ifdef LINUX_NPTL 338 static void 339 linux_userret(l, arg) 340 struct lwp *l; 341 void *arg; 342 { 343 struct proc *p = l->l_proc; 344 struct linux_emuldata *led = p->p_emuldata; 345 int error; 346 347 p->p_userret = NULL; 348 349 /* Emulate LINUX_CLONE_CHILD_SETTID */ 350 if (led->set_tid != NULL) { 351 if ((error = copyout(&p->p_pid, 352 led->set_tid, sizeof(p->p_pid))) != 0) 353 printf("linux_userret: cannot set TID\n"); 354 } 355 356 /* Emulate LINUX_CLONE_NEWTLS */ 357 if (led->set_tls != 0) { 358 if (linux_set_newtls(l, led->set_tls) != 0) 359 printf("linux_userret: cannot set TLS\n"); 360 } 361 362 return; 363 } 364 #endif /* LINUX_NPTL */ 365