1ad2056f2SAlexander Leidinger /*- 2ad2056f2SAlexander Leidinger * Copyright (c) 2006 Roman Divacky 3ad2056f2SAlexander Leidinger * All rights reserved. 4ad2056f2SAlexander Leidinger * 5ad2056f2SAlexander Leidinger * Redistribution and use in source and binary forms, with or without 6ad2056f2SAlexander Leidinger * modification, are permitted provided that the following conditions 7ad2056f2SAlexander Leidinger * are met: 8ad2056f2SAlexander Leidinger * 1. Redistributions of source code must retain the above copyright 9ad2056f2SAlexander Leidinger * notice, this list of conditions and the following disclaimer 10ad2056f2SAlexander Leidinger * in this position and unchanged. 11ad2056f2SAlexander Leidinger * 2. Redistributions in binary form must reproduce the above copyright 12ad2056f2SAlexander Leidinger * notice, this list of conditions and the following disclaimer in the 13ad2056f2SAlexander Leidinger * documentation and/or other materials provided with the distribution. 14ad2056f2SAlexander Leidinger * 3. The name of the author may not be used to endorse or promote products 15ad2056f2SAlexander Leidinger * derived from this software without specific prior written permission 16ad2056f2SAlexander Leidinger * 17ad2056f2SAlexander Leidinger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18ad2056f2SAlexander Leidinger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19ad2056f2SAlexander Leidinger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20ad2056f2SAlexander Leidinger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21ad2056f2SAlexander Leidinger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22ad2056f2SAlexander Leidinger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23ad2056f2SAlexander Leidinger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24ad2056f2SAlexander Leidinger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25ad2056f2SAlexander Leidinger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26ad2056f2SAlexander Leidinger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27ad2056f2SAlexander Leidinger */ 28ad2056f2SAlexander Leidinger 29ad2056f2SAlexander Leidinger #include <sys/cdefs.h> 30ad2056f2SAlexander Leidinger __FBSDID("$FreeBSD$"); 31ad2056f2SAlexander Leidinger 32ad2056f2SAlexander Leidinger #include "opt_compat.h" 33ad2056f2SAlexander Leidinger 34ad2056f2SAlexander Leidinger #include <sys/param.h> 35ad2056f2SAlexander Leidinger #include <sys/systm.h> 36ad2056f2SAlexander Leidinger #include <sys/imgact.h> 37b4bb5154SKonstantin Belousov #include <sys/kernel.h> 38ad2056f2SAlexander Leidinger #include <sys/lock.h> 39ad2056f2SAlexander Leidinger #include <sys/malloc.h> 40ad2056f2SAlexander Leidinger #include <sys/mutex.h> 41ad2056f2SAlexander Leidinger #include <sys/sx.h> 42ad2056f2SAlexander Leidinger #include <sys/proc.h> 43ad2056f2SAlexander Leidinger #include <sys/syscallsubr.h> 44ad2056f2SAlexander Leidinger #include <sys/sysproto.h> 45ad2056f2SAlexander Leidinger #include <sys/unistd.h> 46ad2056f2SAlexander Leidinger 47ad2056f2SAlexander Leidinger #include <compat/linux/linux_emul.h> 48ad2056f2SAlexander Leidinger #include <compat/linux/linux_futex.h> 49ad2056f2SAlexander Leidinger 50ad2056f2SAlexander Leidinger #ifdef COMPAT_LINUX32 51ad2056f2SAlexander Leidinger #include <machine/../linux32/linux.h> 52ad2056f2SAlexander Leidinger #include <machine/../linux32/linux32_proto.h> 53ad2056f2SAlexander Leidinger #else 54ad2056f2SAlexander Leidinger #include <machine/../linux/linux.h> 55ad2056f2SAlexander Leidinger #include <machine/../linux/linux_proto.h> 56ad2056f2SAlexander Leidinger #endif 57ad2056f2SAlexander Leidinger 58ad2056f2SAlexander Leidinger struct sx emul_shared_lock; 59ad2056f2SAlexander Leidinger struct sx emul_lock; 60ad2056f2SAlexander Leidinger 61ad2056f2SAlexander Leidinger /* this returns locked reference to the emuldata entry (if found) */ 62ad2056f2SAlexander Leidinger struct linux_emuldata * 63ad2056f2SAlexander Leidinger em_find(struct proc *p, int locked) 64ad2056f2SAlexander Leidinger { 65ad2056f2SAlexander Leidinger struct linux_emuldata *em; 66ad2056f2SAlexander Leidinger 671c65504cSAlexander Leidinger if (locked == EMUL_DOLOCK) 68ad2056f2SAlexander Leidinger EMUL_LOCK(&emul_lock); 69ad2056f2SAlexander Leidinger 70ad2056f2SAlexander Leidinger em = p->p_emuldata; 71ad2056f2SAlexander Leidinger 721c65504cSAlexander Leidinger if (em == NULL && locked == EMUL_DOLOCK) 73ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 74ad2056f2SAlexander Leidinger 75ad2056f2SAlexander Leidinger return (em); 76ad2056f2SAlexander Leidinger } 77ad2056f2SAlexander Leidinger 78ad2056f2SAlexander Leidinger int 79ad2056f2SAlexander Leidinger linux_proc_init(struct thread *td, pid_t child, int flags) 80ad2056f2SAlexander Leidinger { 81ad2056f2SAlexander Leidinger struct linux_emuldata *em, *p_em; 82ad2056f2SAlexander Leidinger struct proc *p; 83ad2056f2SAlexander Leidinger 84ad2056f2SAlexander Leidinger if (child != 0) { 85ad2056f2SAlexander Leidinger /* non-exec call */ 865342db08SSuleiman Souhlal em = malloc(sizeof *em, M_LINUX, M_WAITOK | M_ZERO); 87ad2056f2SAlexander Leidinger em->pid = child; 88955d762aSAlexander Leidinger em->pdeath_signal = 0; 89292a85f4SKonstantin Belousov if (flags & CLONE_THREAD) { 90ad2056f2SAlexander Leidinger /* handled later in the code */ 91ad2056f2SAlexander Leidinger } else { 92ad2056f2SAlexander Leidinger struct linux_emuldata_shared *s; 93ad2056f2SAlexander Leidinger 945342db08SSuleiman Souhlal s = malloc(sizeof *s, M_LINUX, M_WAITOK | M_ZERO); 95ad2056f2SAlexander Leidinger s->refs = 1; 96ad2056f2SAlexander Leidinger s->group_pid = child; 97ad2056f2SAlexander Leidinger 98ad2056f2SAlexander Leidinger LIST_INIT(&s->threads); 99d071f504SAlexander Leidinger em->shared = s; 100ad2056f2SAlexander Leidinger } 101ad2056f2SAlexander Leidinger } else { 102ad2056f2SAlexander Leidinger /* lookup the old one */ 1031c65504cSAlexander Leidinger em = em_find(td->td_proc, EMUL_DOLOCK); 104ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); 105ad2056f2SAlexander Leidinger } 106ad2056f2SAlexander Leidinger 107ad2056f2SAlexander Leidinger em->child_clear_tid = NULL; 108ad2056f2SAlexander Leidinger em->child_set_tid = NULL; 109ad2056f2SAlexander Leidinger 1100eef2f8aSAlexander Leidinger /* 111a628609eSAlexander Leidinger * allocate the shared struct only in clone()/fork cases in the case 112a628609eSAlexander Leidinger * of clone() td = calling proc and child = pid of the newly created 113a628609eSAlexander Leidinger * proc 114ad2056f2SAlexander Leidinger */ 115ad2056f2SAlexander Leidinger if (child != 0) { 116292a85f4SKonstantin Belousov if (flags & CLONE_THREAD) { 117ad2056f2SAlexander Leidinger /* lookup the parent */ 11825954d74SKonstantin Belousov /* 11925954d74SKonstantin Belousov * we dont have to lock the p_em because 12025954d74SKonstantin Belousov * its waiting for us in linux_clone so 12125954d74SKonstantin Belousov * there is no chance of it changing the 12225954d74SKonstantin Belousov * p_em->shared address 12325954d74SKonstantin Belousov */ 12425954d74SKonstantin Belousov p_em = em_find(td->td_proc, EMUL_DONTLOCK); 125292a85f4SKonstantin Belousov KASSERT(p_em != NULL, ("proc_init: parent emuldata not found for CLONE_THREAD\n")); 126ad2056f2SAlexander Leidinger em->shared = p_em->shared; 12725954d74SKonstantin Belousov EMUL_SHARED_WLOCK(&emul_shared_lock); 128ad2056f2SAlexander Leidinger em->shared->refs++; 129291081ceSAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 130ad2056f2SAlexander Leidinger } else { 131a628609eSAlexander Leidinger /* 132a628609eSAlexander Leidinger * handled earlier to avoid malloc(M_WAITOK) with 133a628609eSAlexander Leidinger * rwlock held 134a628609eSAlexander Leidinger */ 135ad2056f2SAlexander Leidinger } 136ad2056f2SAlexander Leidinger } 137ad2056f2SAlexander Leidinger if (child != 0) { 138ad2056f2SAlexander Leidinger EMUL_SHARED_WLOCK(&emul_shared_lock); 139ad2056f2SAlexander Leidinger LIST_INSERT_HEAD(&em->shared->threads, em, threads); 140ad2056f2SAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 141ad2056f2SAlexander Leidinger 142ad2056f2SAlexander Leidinger p = pfind(child); 143d071f504SAlexander Leidinger KASSERT(p != NULL, ("process not found in proc_init\n")); 144d071f504SAlexander Leidinger p->p_emuldata = em; 1458618fd85SAlexander Leidinger PROC_UNLOCK(p); 146ad2056f2SAlexander Leidinger } else 147ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 148ad2056f2SAlexander Leidinger 149ad2056f2SAlexander Leidinger return (0); 150ad2056f2SAlexander Leidinger } 151ad2056f2SAlexander Leidinger 152ad2056f2SAlexander Leidinger void 153ad2056f2SAlexander Leidinger linux_proc_exit(void *arg __unused, struct proc *p) 154ad2056f2SAlexander Leidinger { 155ad2056f2SAlexander Leidinger struct linux_emuldata *em; 156ad2056f2SAlexander Leidinger int error; 157ad2056f2SAlexander Leidinger struct thread *td = FIRST_THREAD_IN_PROC(p); 158ad2056f2SAlexander Leidinger int *child_clear_tid; 159955d762aSAlexander Leidinger struct proc *q, *nq; 160ad2056f2SAlexander Leidinger 161ad2056f2SAlexander Leidinger if (__predict_true(p->p_sysent != &elf_linux_sysvec)) 162ad2056f2SAlexander Leidinger return; 163ad2056f2SAlexander Leidinger 164ad2056f2SAlexander Leidinger /* find the emuldata */ 1651c65504cSAlexander Leidinger em = em_find(p, EMUL_DOLOCK); 166ad2056f2SAlexander Leidinger 167ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("proc_exit: emuldata not found.\n")); 168ad2056f2SAlexander Leidinger 16925954d74SKonstantin Belousov /* reparent all procs that are not a thread leader to initproc */ 17025954d74SKonstantin Belousov if (em->shared->group_pid != p->p_pid) { 171e8b8b834SAlexander Leidinger child_clear_tid = em->child_clear_tid; 172e8b8b834SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 17325954d74SKonstantin Belousov sx_xlock(&proctree_lock); 17425954d74SKonstantin Belousov wakeup(initproc); 17525954d74SKonstantin Belousov PROC_LOCK(p); 17625954d74SKonstantin Belousov proc_reparent(p, initproc); 17725954d74SKonstantin Belousov p->p_sigparent = SIGCHLD; 17825954d74SKonstantin Belousov PROC_UNLOCK(p); 17925954d74SKonstantin Belousov sx_xunlock(&proctree_lock); 180e8b8b834SAlexander Leidinger } else { 181ad2056f2SAlexander Leidinger child_clear_tid = em->child_clear_tid; 182ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 183e8b8b834SAlexander Leidinger } 184ad2056f2SAlexander Leidinger 185ad2056f2SAlexander Leidinger EMUL_SHARED_WLOCK(&emul_shared_lock); 186ad2056f2SAlexander Leidinger LIST_REMOVE(em, threads); 187ad2056f2SAlexander Leidinger 188ad2056f2SAlexander Leidinger em->shared->refs--; 189ad2056f2SAlexander Leidinger if (em->shared->refs == 0) 1905342db08SSuleiman Souhlal free(em->shared, M_LINUX); 191ad2056f2SAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 192ad2056f2SAlexander Leidinger 193ad2056f2SAlexander Leidinger if (child_clear_tid != NULL) { 194ad2056f2SAlexander Leidinger struct linux_sys_futex_args cup; 195ad2056f2SAlexander Leidinger int null = 0; 196ad2056f2SAlexander Leidinger 197ad2056f2SAlexander Leidinger error = copyout(&null, child_clear_tid, sizeof(null)); 19828638377SAlexander Leidinger if (error) { 19928638377SAlexander Leidinger free(em, M_LINUX); 200ad2056f2SAlexander Leidinger return; 20128638377SAlexander Leidinger } 202ad2056f2SAlexander Leidinger 203ad2056f2SAlexander Leidinger /* futexes stuff */ 204ad2056f2SAlexander Leidinger cup.uaddr = child_clear_tid; 205ad2056f2SAlexander Leidinger cup.op = LINUX_FUTEX_WAKE; 206ad2056f2SAlexander Leidinger cup.val = 0x7fffffff; /* Awake everyone */ 207ad2056f2SAlexander Leidinger cup.timeout = NULL; 208ad2056f2SAlexander Leidinger cup.uaddr2 = NULL; 209ad2056f2SAlexander Leidinger cup.val3 = 0; 210ad2056f2SAlexander Leidinger error = linux_sys_futex(FIRST_THREAD_IN_PROC(p), &cup); 2110eef2f8aSAlexander Leidinger /* 212a628609eSAlexander Leidinger * this cannot happen at the moment and if this happens it 213a628609eSAlexander Leidinger * probably mean there is a userspace bug 214ad2056f2SAlexander Leidinger */ 215ad2056f2SAlexander Leidinger if (error) 216ad2056f2SAlexander Leidinger printf(LMSG("futex stuff in proc_exit failed.\n")); 217ad2056f2SAlexander Leidinger } 218ad2056f2SAlexander Leidinger 219ad2056f2SAlexander Leidinger /* clean the stuff up */ 2205342db08SSuleiman Souhlal free(em, M_LINUX); 221955d762aSAlexander Leidinger 222955d762aSAlexander Leidinger /* this is a little weird but rewritten from exit1() */ 223955d762aSAlexander Leidinger sx_xlock(&proctree_lock); 224955d762aSAlexander Leidinger q = LIST_FIRST(&p->p_children); 225955d762aSAlexander Leidinger for (; q != NULL; q = nq) { 226955d762aSAlexander Leidinger nq = LIST_NEXT(q, p_sibling); 227955d762aSAlexander Leidinger if (q->p_flag & P_WEXIT) 228955d762aSAlexander Leidinger continue; 229955d762aSAlexander Leidinger if (__predict_false(q->p_sysent != &elf_linux_sysvec)) 230955d762aSAlexander Leidinger continue; 2311c65504cSAlexander Leidinger em = em_find(q, EMUL_DOLOCK); 232955d762aSAlexander Leidinger KASSERT(em != NULL, ("linux_reparent: emuldata not found: %i\n", q->p_pid)); 233955d762aSAlexander Leidinger if (em->pdeath_signal != 0) { 234955d762aSAlexander Leidinger PROC_LOCK(q); 235955d762aSAlexander Leidinger psignal(q, em->pdeath_signal); 236955d762aSAlexander Leidinger PROC_UNLOCK(q); 237955d762aSAlexander Leidinger } 238955d762aSAlexander Leidinger EMUL_UNLOCK(&emul_lock); 239955d762aSAlexander Leidinger } 240955d762aSAlexander Leidinger sx_xunlock(&proctree_lock); 241ad2056f2SAlexander Leidinger } 242ad2056f2SAlexander Leidinger 2430eef2f8aSAlexander Leidinger /* 2440eef2f8aSAlexander Leidinger * This is used in a case of transition from FreeBSD binary execing to linux binary 245ad2056f2SAlexander Leidinger * in this case we create linux emuldata proc entry with the pid of the currently running 246ad2056f2SAlexander Leidinger * process. 247ad2056f2SAlexander Leidinger */ 248a628609eSAlexander Leidinger void 249a628609eSAlexander Leidinger linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) 250ad2056f2SAlexander Leidinger { 251ad2056f2SAlexander Leidinger if (__predict_false(imgp->sysent == &elf_linux_sysvec 252ad2056f2SAlexander Leidinger && p->p_sysent != &elf_linux_sysvec)) 253ad2056f2SAlexander Leidinger linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0); 254ad2056f2SAlexander Leidinger if (__predict_false(imgp->sysent != &elf_linux_sysvec 255ad2056f2SAlexander Leidinger && p->p_sysent == &elf_linux_sysvec)) { 256ad2056f2SAlexander Leidinger struct linux_emuldata *em; 257ad2056f2SAlexander Leidinger 25825954d74SKonstantin Belousov /* 25925954d74SKonstantin Belousov * XXX:There's a race because here we assign p->p_emuldata NULL 26025954d74SKonstantin Belousov * but the process is still counted as linux one for a short 26125954d74SKonstantin Belousov * time so some other process might reference it and try to 26225954d74SKonstantin Belousov * access its p->p_emuldata and panicing on a NULL reference. 26325954d74SKonstantin Belousov */ 26425954d74SKonstantin Belousov em = em_find(p, EMUL_DONTLOCK); 265ad2056f2SAlexander Leidinger 266ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("proc_exec: emuldata not found.\n")); 267ad2056f2SAlexander Leidinger 268ad2056f2SAlexander Leidinger EMUL_SHARED_WLOCK(&emul_shared_lock); 269ad2056f2SAlexander Leidinger LIST_REMOVE(em, threads); 270ad2056f2SAlexander Leidinger 271ad2056f2SAlexander Leidinger PROC_LOCK(p); 272ad2056f2SAlexander Leidinger p->p_emuldata = NULL; 273ad2056f2SAlexander Leidinger PROC_UNLOCK(p); 274ad2056f2SAlexander Leidinger 275ad2056f2SAlexander Leidinger em->shared->refs--; 276ad2056f2SAlexander Leidinger if (em->shared->refs == 0) 277c67e0cc9SSuleiman Souhlal free(em->shared, M_LINUX); 278ad2056f2SAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 279ad2056f2SAlexander Leidinger 280c67e0cc9SSuleiman Souhlal free(em, M_LINUX); 281ad2056f2SAlexander Leidinger } 282ad2056f2SAlexander Leidinger } 283ad2056f2SAlexander Leidinger 284ad2056f2SAlexander Leidinger void 285ad2056f2SAlexander Leidinger linux_schedtail(void *arg __unused, struct proc *p) 286ad2056f2SAlexander Leidinger { 287ad2056f2SAlexander Leidinger struct linux_emuldata *em; 288ad2056f2SAlexander Leidinger int error = 0; 289ad2056f2SAlexander Leidinger int *child_set_tid; 290ad2056f2SAlexander Leidinger 291955d762aSAlexander Leidinger if (__predict_true(p->p_sysent != &elf_linux_sysvec)) 292ad2056f2SAlexander Leidinger return; 293ad2056f2SAlexander Leidinger 294ad2056f2SAlexander Leidinger /* find the emuldata */ 2951c65504cSAlexander Leidinger em = em_find(p, EMUL_DOLOCK); 296ad2056f2SAlexander Leidinger 29725954d74SKonstantin Belousov KASSERT(em != NULL, ("linux_schedtail: emuldata not found.\n")); 298ad2056f2SAlexander Leidinger child_set_tid = em->child_set_tid; 299ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 300ad2056f2SAlexander Leidinger 301ad2056f2SAlexander Leidinger if (child_set_tid != NULL) 302a628609eSAlexander Leidinger error = copyout(&p->p_pid, (int *)child_set_tid, 303a628609eSAlexander Leidinger sizeof(p->p_pid)); 304ad2056f2SAlexander Leidinger 305ad2056f2SAlexander Leidinger return; 306ad2056f2SAlexander Leidinger } 307ad2056f2SAlexander Leidinger 308ad2056f2SAlexander Leidinger int 309ad2056f2SAlexander Leidinger linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) 310ad2056f2SAlexander Leidinger { 311ad2056f2SAlexander Leidinger struct linux_emuldata *em; 312ad2056f2SAlexander Leidinger 313ad2056f2SAlexander Leidinger #ifdef DEBUG 314ad2056f2SAlexander Leidinger if (ldebug(set_tid_address)) 315ad2056f2SAlexander Leidinger printf(ARGS(set_tid_address, "%p"), args->tidptr); 316ad2056f2SAlexander Leidinger #endif 317ad2056f2SAlexander Leidinger 318ad2056f2SAlexander Leidinger /* find the emuldata */ 3191c65504cSAlexander Leidinger em = em_find(td->td_proc, EMUL_DOLOCK); 320ad2056f2SAlexander Leidinger 321ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); 322ad2056f2SAlexander Leidinger 323ad2056f2SAlexander Leidinger em->child_clear_tid = args->tidptr; 324ad2056f2SAlexander Leidinger td->td_retval[0] = td->td_proc->p_pid; 325ad2056f2SAlexander Leidinger 326ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 327ad2056f2SAlexander Leidinger return 0; 328ad2056f2SAlexander Leidinger } 329