/* $NetBSD: linux_exec.c,v 1.124 2020/05/03 01:06:56 thorpej Exp $ */ /*- * Copyright (c) 1994, 1995, 1998, 2000, 2007, 2008, 2020 * The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Christos Zoulas, Frank van der Linden, Eric Haszlakiewicz and * Thor Lancelot Simon. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.124 2020/05/03 01:06:56 thorpej Exp $"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* For proc_reparent() */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern struct sysent linux_sysent[]; extern const uint32_t linux_sysent_nomodbits[]; extern const char * const linux_syscallnames[]; extern char linux_sigcode[], linux_esigcode[]; /* * Emulation switch. */ struct uvm_object *emul_linux_object; struct emul emul_linux = { .e_name = "linux", .e_path = "/emul/linux", #ifndef __HAVE_MINIMAL_EMUL .e_flags = 0, .e_errno = native_to_linux_errno, .e_nosys = LINUX_SYS_syscall, .e_nsysent = LINUX_SYS_NSYSENT, #endif .e_sysent = linux_sysent, .e_nomodbits = linux_sysent_nomodbits, .e_syscallnames = linux_syscallnames, .e_sendsig = linux_sendsig, .e_trapsignal = linux_trapsignal, .e_sigcode = linux_sigcode, .e_esigcode = linux_esigcode, .e_sigobject = &emul_linux_object, .e_setregs = linux_setregs, .e_proc_exec = linux_e_proc_exec, .e_proc_fork = linux_e_proc_fork, .e_proc_exit = linux_e_proc_exit, .e_lwp_fork = linux_e_lwp_fork, .e_lwp_exit = linux_e_lwp_exit, #ifdef __HAVE_SYSCALL_INTERN .e_syscall_intern = linux_syscall_intern, #else #error Implement __HAVE_SYSCALL_INTERN for this platform #endif .e_sysctlovly = NULL, .e_vm_default_addr = uvm_default_mapaddr, .e_usertrap = linux_usertrap, .e_ucsize = 0, .e_startlwp = NULL }; void linux_e_proc_exec(struct proc *p, struct exec_package *epp) { struct lwp *l; l = LIST_FIRST(&p->p_lwps); if (l->l_emuldata == NULL) { l->l_emuldata = kmem_zalloc(sizeof(struct linux_emuldata), KM_SLEEP); } else { memset(l->l_emuldata, 0, sizeof (struct linux_emuldata)); } KASSERT(p->p_nlwps == 1); } void linux_e_proc_exit(struct proc *p) { struct lwp *l; KASSERT(p->p_nlwps == 1); l = LIST_FIRST(&p->p_lwps); linux_e_lwp_exit(l); } void linux_e_proc_fork(struct proc *p2, struct lwp *l1, int flags) { struct linux_emuldata *led1, *led2; struct lwp *l2; KASSERT(p2->p_nlwps == 1); l2 = LIST_FIRST(&p2->p_lwps); led1 = l1->l_emuldata; led2 = l2->l_emuldata; led2->led_child_tidptr = led1->led_child_tidptr; } void linux_e_lwp_fork(struct lwp *l1, struct lwp *l2) { struct linux_emuldata *led2; led2 = kmem_zalloc(sizeof(*led2), KM_SLEEP); l2->l_emuldata = led2; } void linux_e_lwp_exit(struct lwp *l) { struct linux_emuldata *led; register_t retval; int error, zero = 0; led = l->l_emuldata; if (led->led_clear_tid != NULL) { /* Emulate LINUX_CLONE_CHILD_CLEARTID */ error = copyout(&zero, led->led_clear_tid, sizeof(zero)); #ifdef DEBUG_LINUX if (error != 0) printf("%s: cannot clear TID\n", __func__); #endif error = linux_do_futex((int *)led->led_clear_tid, FUTEX_WAKE, INT_MAX, NULL, NULL, 0, 0, &retval); if (error) printf("%s: linux_sys_futex failed\n", __func__); } led = l->l_emuldata; l->l_emuldata = NULL; kmem_free(led, sizeof(*led)); }