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 #ifdef COMPAT_LINUX32 48ad2056f2SAlexander Leidinger #include <machine/../linux32/linux.h> 49ad2056f2SAlexander Leidinger #include <machine/../linux32/linux32_proto.h> 50ad2056f2SAlexander Leidinger #else 51ad2056f2SAlexander Leidinger #include <machine/../linux/linux.h> 52ad2056f2SAlexander Leidinger #include <machine/../linux/linux_proto.h> 53ad2056f2SAlexander Leidinger #endif 54ad2056f2SAlexander Leidinger 554732e446SRoman Divacky #include <compat/linux/linux_emul.h> 564732e446SRoman Divacky #include <compat/linux/linux_futex.h> 574732e446SRoman Divacky 58ad2056f2SAlexander Leidinger struct sx emul_shared_lock; 59357afa71SJung-uk Kim struct mtx 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; 894732e446SRoman Divacky em->robust_futexes = NULL; 90a4e3bad7SJung-uk Kim if (flags & LINUX_CLONE_THREAD) { 91ad2056f2SAlexander Leidinger /* handled later in the code */ 92ad2056f2SAlexander Leidinger } else { 93ad2056f2SAlexander Leidinger struct linux_emuldata_shared *s; 94ad2056f2SAlexander Leidinger 955342db08SSuleiman Souhlal s = malloc(sizeof *s, M_LINUX, M_WAITOK | M_ZERO); 96ad2056f2SAlexander Leidinger s->refs = 1; 97ad2056f2SAlexander Leidinger s->group_pid = child; 98ad2056f2SAlexander Leidinger 99ad2056f2SAlexander Leidinger LIST_INIT(&s->threads); 100d071f504SAlexander Leidinger em->shared = s; 101ad2056f2SAlexander Leidinger } 102ad2056f2SAlexander Leidinger } else { 103ad2056f2SAlexander Leidinger /* lookup the old one */ 1041c65504cSAlexander Leidinger em = em_find(td->td_proc, EMUL_DOLOCK); 105ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); 106ad2056f2SAlexander Leidinger } 107ad2056f2SAlexander Leidinger 108ad2056f2SAlexander Leidinger em->child_clear_tid = NULL; 109ad2056f2SAlexander Leidinger em->child_set_tid = NULL; 110ad2056f2SAlexander Leidinger 1110eef2f8aSAlexander Leidinger /* 112a628609eSAlexander Leidinger * allocate the shared struct only in clone()/fork cases in the case 113a628609eSAlexander Leidinger * of clone() td = calling proc and child = pid of the newly created 114a628609eSAlexander Leidinger * proc 115ad2056f2SAlexander Leidinger */ 116ad2056f2SAlexander Leidinger if (child != 0) { 117a4e3bad7SJung-uk Kim if (flags & LINUX_CLONE_THREAD) { 118ad2056f2SAlexander Leidinger /* lookup the parent */ 11925954d74SKonstantin Belousov /* 12025954d74SKonstantin Belousov * we dont have to lock the p_em because 12125954d74SKonstantin Belousov * its waiting for us in linux_clone so 12225954d74SKonstantin Belousov * there is no chance of it changing the 12325954d74SKonstantin Belousov * p_em->shared address 12425954d74SKonstantin Belousov */ 12525954d74SKonstantin Belousov p_em = em_find(td->td_proc, EMUL_DONTLOCK); 126292a85f4SKonstantin Belousov KASSERT(p_em != NULL, ("proc_init: parent emuldata not found for CLONE_THREAD\n")); 127ad2056f2SAlexander Leidinger em->shared = p_em->shared; 12825954d74SKonstantin Belousov EMUL_SHARED_WLOCK(&emul_shared_lock); 129ad2056f2SAlexander Leidinger em->shared->refs++; 130291081ceSAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 131ad2056f2SAlexander Leidinger } else { 132a628609eSAlexander Leidinger /* 133a628609eSAlexander Leidinger * handled earlier to avoid malloc(M_WAITOK) with 134a628609eSAlexander Leidinger * rwlock held 135a628609eSAlexander Leidinger */ 136ad2056f2SAlexander Leidinger } 137ad2056f2SAlexander Leidinger } 138ad2056f2SAlexander Leidinger if (child != 0) { 139ad2056f2SAlexander Leidinger EMUL_SHARED_WLOCK(&emul_shared_lock); 140ad2056f2SAlexander Leidinger LIST_INSERT_HEAD(&em->shared->threads, em, threads); 141ad2056f2SAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 142ad2056f2SAlexander Leidinger 143ad2056f2SAlexander Leidinger p = pfind(child); 144d071f504SAlexander Leidinger KASSERT(p != NULL, ("process not found in proc_init\n")); 145d071f504SAlexander Leidinger p->p_emuldata = em; 1468618fd85SAlexander Leidinger PROC_UNLOCK(p); 147ad2056f2SAlexander Leidinger } else 148ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 149ad2056f2SAlexander Leidinger 150ad2056f2SAlexander Leidinger return (0); 151ad2056f2SAlexander Leidinger } 152ad2056f2SAlexander Leidinger 153ad2056f2SAlexander Leidinger void 154ad2056f2SAlexander Leidinger linux_proc_exit(void *arg __unused, struct proc *p) 155ad2056f2SAlexander Leidinger { 156ad2056f2SAlexander Leidinger struct linux_emuldata *em; 157ad2056f2SAlexander Leidinger int error; 158ad2056f2SAlexander Leidinger struct thread *td = FIRST_THREAD_IN_PROC(p); 159ad2056f2SAlexander Leidinger int *child_clear_tid; 160955d762aSAlexander Leidinger struct proc *q, *nq; 161ad2056f2SAlexander Leidinger 162ad2056f2SAlexander Leidinger if (__predict_true(p->p_sysent != &elf_linux_sysvec)) 163ad2056f2SAlexander Leidinger return; 164ad2056f2SAlexander Leidinger 1654732e446SRoman Divacky release_futexes(p); 1664732e446SRoman Divacky 167ad2056f2SAlexander Leidinger /* find the emuldata */ 1681c65504cSAlexander Leidinger em = em_find(p, EMUL_DOLOCK); 169ad2056f2SAlexander Leidinger 170ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("proc_exit: emuldata not found.\n")); 171ad2056f2SAlexander Leidinger 17225954d74SKonstantin Belousov /* reparent all procs that are not a thread leader to initproc */ 17325954d74SKonstantin Belousov if (em->shared->group_pid != p->p_pid) { 174e8b8b834SAlexander Leidinger child_clear_tid = em->child_clear_tid; 175e8b8b834SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 17625954d74SKonstantin Belousov sx_xlock(&proctree_lock); 17725954d74SKonstantin Belousov wakeup(initproc); 17825954d74SKonstantin Belousov PROC_LOCK(p); 17925954d74SKonstantin Belousov proc_reparent(p, initproc); 18025954d74SKonstantin Belousov p->p_sigparent = SIGCHLD; 18125954d74SKonstantin Belousov PROC_UNLOCK(p); 18225954d74SKonstantin Belousov sx_xunlock(&proctree_lock); 183e8b8b834SAlexander Leidinger } else { 184ad2056f2SAlexander Leidinger child_clear_tid = em->child_clear_tid; 185ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 186e8b8b834SAlexander Leidinger } 187ad2056f2SAlexander Leidinger 188ad2056f2SAlexander Leidinger EMUL_SHARED_WLOCK(&emul_shared_lock); 189ad2056f2SAlexander Leidinger LIST_REMOVE(em, threads); 190ad2056f2SAlexander Leidinger 191ad2056f2SAlexander Leidinger em->shared->refs--; 1921a26db0aSAlexander Leidinger if (em->shared->refs == 0) { 1931a26db0aSAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 1945342db08SSuleiman Souhlal free(em->shared, M_LINUX); 1951a26db0aSAlexander Leidinger } else 196ad2056f2SAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 197ad2056f2SAlexander Leidinger 198ad2056f2SAlexander Leidinger if (child_clear_tid != NULL) { 199ad2056f2SAlexander Leidinger struct linux_sys_futex_args cup; 200ad2056f2SAlexander Leidinger int null = 0; 201ad2056f2SAlexander Leidinger 202ad2056f2SAlexander Leidinger error = copyout(&null, child_clear_tid, sizeof(null)); 20328638377SAlexander Leidinger if (error) { 20428638377SAlexander Leidinger free(em, M_LINUX); 205ad2056f2SAlexander Leidinger return; 20628638377SAlexander Leidinger } 207ad2056f2SAlexander Leidinger 208ad2056f2SAlexander Leidinger /* futexes stuff */ 209ad2056f2SAlexander Leidinger cup.uaddr = child_clear_tid; 210ad2056f2SAlexander Leidinger cup.op = LINUX_FUTEX_WAKE; 211ad2056f2SAlexander Leidinger cup.val = 0x7fffffff; /* Awake everyone */ 212ad2056f2SAlexander Leidinger cup.timeout = NULL; 213ad2056f2SAlexander Leidinger cup.uaddr2 = NULL; 214ad2056f2SAlexander Leidinger cup.val3 = 0; 215ad2056f2SAlexander Leidinger error = linux_sys_futex(FIRST_THREAD_IN_PROC(p), &cup); 2160eef2f8aSAlexander Leidinger /* 217a628609eSAlexander Leidinger * this cannot happen at the moment and if this happens it 218802e08a3SAlexander Leidinger * probably means there is a user space bug 219ad2056f2SAlexander Leidinger */ 220ad2056f2SAlexander Leidinger if (error) 221ad2056f2SAlexander Leidinger printf(LMSG("futex stuff in proc_exit failed.\n")); 222ad2056f2SAlexander Leidinger } 223ad2056f2SAlexander Leidinger 224ad2056f2SAlexander Leidinger /* clean the stuff up */ 2255342db08SSuleiman Souhlal free(em, M_LINUX); 226955d762aSAlexander Leidinger 227955d762aSAlexander Leidinger /* this is a little weird but rewritten from exit1() */ 228955d762aSAlexander Leidinger sx_xlock(&proctree_lock); 229955d762aSAlexander Leidinger q = LIST_FIRST(&p->p_children); 230955d762aSAlexander Leidinger for (; q != NULL; q = nq) { 231955d762aSAlexander Leidinger nq = LIST_NEXT(q, p_sibling); 232955d762aSAlexander Leidinger if (q->p_flag & P_WEXIT) 233955d762aSAlexander Leidinger continue; 234955d762aSAlexander Leidinger if (__predict_false(q->p_sysent != &elf_linux_sysvec)) 235955d762aSAlexander Leidinger continue; 2361c65504cSAlexander Leidinger em = em_find(q, EMUL_DOLOCK); 237955d762aSAlexander Leidinger KASSERT(em != NULL, ("linux_reparent: emuldata not found: %i\n", q->p_pid)); 238955d762aSAlexander Leidinger if (em->pdeath_signal != 0) { 239955d762aSAlexander Leidinger PROC_LOCK(q); 240955d762aSAlexander Leidinger psignal(q, em->pdeath_signal); 241955d762aSAlexander Leidinger PROC_UNLOCK(q); 242955d762aSAlexander Leidinger } 243955d762aSAlexander Leidinger EMUL_UNLOCK(&emul_lock); 244955d762aSAlexander Leidinger } 245955d762aSAlexander Leidinger sx_xunlock(&proctree_lock); 246ad2056f2SAlexander Leidinger } 247ad2056f2SAlexander Leidinger 2480eef2f8aSAlexander Leidinger /* 2490eef2f8aSAlexander Leidinger * This is used in a case of transition from FreeBSD binary execing to linux binary 250ad2056f2SAlexander Leidinger * in this case we create linux emuldata proc entry with the pid of the currently running 251ad2056f2SAlexander Leidinger * process. 252ad2056f2SAlexander Leidinger */ 253a628609eSAlexander Leidinger void 254a628609eSAlexander Leidinger linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) 255ad2056f2SAlexander Leidinger { 256ad2056f2SAlexander Leidinger if (__predict_false(imgp->sysent == &elf_linux_sysvec 257ad2056f2SAlexander Leidinger && p->p_sysent != &elf_linux_sysvec)) 258ad2056f2SAlexander Leidinger linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0); 259ad2056f2SAlexander Leidinger if (__predict_false(imgp->sysent != &elf_linux_sysvec 260ad2056f2SAlexander Leidinger && p->p_sysent == &elf_linux_sysvec)) { 261ad2056f2SAlexander Leidinger struct linux_emuldata *em; 262ad2056f2SAlexander Leidinger 26325954d74SKonstantin Belousov /* 26425954d74SKonstantin Belousov * XXX:There's a race because here we assign p->p_emuldata NULL 26525954d74SKonstantin Belousov * but the process is still counted as linux one for a short 26625954d74SKonstantin Belousov * time so some other process might reference it and try to 26725954d74SKonstantin Belousov * access its p->p_emuldata and panicing on a NULL reference. 26825954d74SKonstantin Belousov */ 26925954d74SKonstantin Belousov em = em_find(p, EMUL_DONTLOCK); 270ad2056f2SAlexander Leidinger 271ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("proc_exec: emuldata not found.\n")); 272ad2056f2SAlexander Leidinger 273ad2056f2SAlexander Leidinger EMUL_SHARED_WLOCK(&emul_shared_lock); 274ad2056f2SAlexander Leidinger LIST_REMOVE(em, threads); 275ad2056f2SAlexander Leidinger 276ad2056f2SAlexander Leidinger PROC_LOCK(p); 277ad2056f2SAlexander Leidinger p->p_emuldata = NULL; 278ad2056f2SAlexander Leidinger PROC_UNLOCK(p); 279ad2056f2SAlexander Leidinger 280ad2056f2SAlexander Leidinger em->shared->refs--; 2811a26db0aSAlexander Leidinger if (em->shared->refs == 0) { 2821a26db0aSAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 283c67e0cc9SSuleiman Souhlal free(em->shared, M_LINUX); 2841a26db0aSAlexander Leidinger } else 285ad2056f2SAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 286ad2056f2SAlexander Leidinger 287c67e0cc9SSuleiman Souhlal free(em, M_LINUX); 288ad2056f2SAlexander Leidinger } 289ad2056f2SAlexander Leidinger } 290ad2056f2SAlexander Leidinger 291ad2056f2SAlexander Leidinger void 292ad2056f2SAlexander Leidinger linux_schedtail(void *arg __unused, struct proc *p) 293ad2056f2SAlexander Leidinger { 294ad2056f2SAlexander Leidinger struct linux_emuldata *em; 295ad2056f2SAlexander Leidinger int error = 0; 296ad2056f2SAlexander Leidinger int *child_set_tid; 297ad2056f2SAlexander Leidinger 298955d762aSAlexander Leidinger if (__predict_true(p->p_sysent != &elf_linux_sysvec)) 299ad2056f2SAlexander Leidinger return; 300ad2056f2SAlexander Leidinger 301ad2056f2SAlexander Leidinger /* find the emuldata */ 3021c65504cSAlexander Leidinger em = em_find(p, EMUL_DOLOCK); 303ad2056f2SAlexander Leidinger 30425954d74SKonstantin Belousov KASSERT(em != NULL, ("linux_schedtail: emuldata not found.\n")); 305ad2056f2SAlexander Leidinger child_set_tid = em->child_set_tid; 306ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 307ad2056f2SAlexander Leidinger 308ad2056f2SAlexander Leidinger if (child_set_tid != NULL) 309a628609eSAlexander Leidinger error = copyout(&p->p_pid, (int *)child_set_tid, 310a628609eSAlexander Leidinger sizeof(p->p_pid)); 311ad2056f2SAlexander Leidinger 312ad2056f2SAlexander Leidinger return; 313ad2056f2SAlexander Leidinger } 314ad2056f2SAlexander Leidinger 315ad2056f2SAlexander Leidinger int 316ad2056f2SAlexander Leidinger linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) 317ad2056f2SAlexander Leidinger { 318ad2056f2SAlexander Leidinger struct linux_emuldata *em; 319ad2056f2SAlexander Leidinger 320ad2056f2SAlexander Leidinger #ifdef DEBUG 321ad2056f2SAlexander Leidinger if (ldebug(set_tid_address)) 322ad2056f2SAlexander Leidinger printf(ARGS(set_tid_address, "%p"), args->tidptr); 323ad2056f2SAlexander Leidinger #endif 324ad2056f2SAlexander Leidinger 325ad2056f2SAlexander Leidinger /* find the emuldata */ 3261c65504cSAlexander Leidinger em = em_find(td->td_proc, EMUL_DOLOCK); 327ad2056f2SAlexander Leidinger 328ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); 329ad2056f2SAlexander Leidinger 330ad2056f2SAlexander Leidinger em->child_clear_tid = args->tidptr; 331ad2056f2SAlexander Leidinger td->td_retval[0] = td->td_proc->p_pid; 332ad2056f2SAlexander Leidinger 333ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 334ad2056f2SAlexander Leidinger return 0; 335ad2056f2SAlexander Leidinger } 336