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> 37ad2056f2SAlexander Leidinger #include <sys/lock.h> 38ad2056f2SAlexander Leidinger #include <sys/malloc.h> 39ad2056f2SAlexander Leidinger #include <sys/mutex.h> 40ad2056f2SAlexander Leidinger #include <sys/sx.h> 41ad2056f2SAlexander Leidinger #include <sys/proc.h> 42ad2056f2SAlexander Leidinger #include <sys/syscallsubr.h> 43ad2056f2SAlexander Leidinger #include <sys/sysproto.h> 44ad2056f2SAlexander Leidinger #include <sys/unistd.h> 45ad2056f2SAlexander Leidinger 46ad2056f2SAlexander Leidinger #include <compat/linux/linux_emul.h> 47ad2056f2SAlexander Leidinger #include <compat/linux/linux_futex.h> 48ad2056f2SAlexander Leidinger 49ad2056f2SAlexander Leidinger #ifdef COMPAT_LINUX32 50ad2056f2SAlexander Leidinger #include <machine/../linux32/linux.h> 51ad2056f2SAlexander Leidinger #include <machine/../linux32/linux32_proto.h> 52ad2056f2SAlexander Leidinger #else 53ad2056f2SAlexander Leidinger #include <machine/../linux/linux.h> 54ad2056f2SAlexander Leidinger #include <machine/../linux/linux_proto.h> 55ad2056f2SAlexander Leidinger #endif 56ad2056f2SAlexander Leidinger 57ad2056f2SAlexander Leidinger struct sx emul_shared_lock; 58ad2056f2SAlexander Leidinger struct sx emul_lock; 59ad2056f2SAlexander Leidinger 60ad2056f2SAlexander Leidinger /* this returns locked reference to the emuldata entry (if found) */ 61ad2056f2SAlexander Leidinger struct linux_emuldata * 62ad2056f2SAlexander Leidinger em_find(struct proc *p, int locked) 63ad2056f2SAlexander Leidinger { 64ad2056f2SAlexander Leidinger struct linux_emuldata *em; 65ad2056f2SAlexander Leidinger 66ad2056f2SAlexander Leidinger if (locked == EMUL_UNLOCKED) 67ad2056f2SAlexander Leidinger EMUL_LOCK(&emul_lock); 68ad2056f2SAlexander Leidinger 69ad2056f2SAlexander Leidinger em = p->p_emuldata; 70ad2056f2SAlexander Leidinger 71ad2056f2SAlexander Leidinger if (em == NULL && locked == EMUL_UNLOCKED) 72ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 73ad2056f2SAlexander Leidinger 74ad2056f2SAlexander Leidinger return (em); 75ad2056f2SAlexander Leidinger } 76ad2056f2SAlexander Leidinger 77ad2056f2SAlexander Leidinger int 78ad2056f2SAlexander Leidinger linux_proc_init(struct thread *td, pid_t child, int flags) 79ad2056f2SAlexander Leidinger { 80ad2056f2SAlexander Leidinger struct linux_emuldata *em, *p_em; 81ad2056f2SAlexander Leidinger struct proc *p; 82ad2056f2SAlexander Leidinger 83ad2056f2SAlexander Leidinger if (child != 0) { 84ad2056f2SAlexander Leidinger /* non-exec call */ 85ad2056f2SAlexander Leidinger MALLOC(em, struct linux_emuldata *, sizeof *em, M_LINUX, M_WAITOK | M_ZERO); 86ad2056f2SAlexander Leidinger em->pid = child; 87ad2056f2SAlexander Leidinger if (flags & CLONE_VM) { 88ad2056f2SAlexander Leidinger /* handled later in the code */ 89ad2056f2SAlexander Leidinger } else { 90ad2056f2SAlexander Leidinger struct linux_emuldata_shared *s; 91ad2056f2SAlexander Leidinger 92ad2056f2SAlexander Leidinger MALLOC(s, struct linux_emuldata_shared *, sizeof *s, M_LINUX, M_WAITOK | M_ZERO); 93ad2056f2SAlexander Leidinger em->shared = s; 94ad2056f2SAlexander Leidinger s->refs = 1; 95ad2056f2SAlexander Leidinger s->group_pid = child; 96ad2056f2SAlexander Leidinger 97ad2056f2SAlexander Leidinger LIST_INIT(&s->threads); 98ad2056f2SAlexander Leidinger } 99ad2056f2SAlexander Leidinger p = pfind(child); 100ad2056f2SAlexander Leidinger if (p == NULL) 101ad2056f2SAlexander Leidinger panic("process not found in proc_init\n"); 102ad2056f2SAlexander Leidinger p->p_emuldata = em; 103ad2056f2SAlexander Leidinger PROC_UNLOCK(p); 104ad2056f2SAlexander Leidinger } else { 105ad2056f2SAlexander Leidinger /* lookup the old one */ 106ad2056f2SAlexander Leidinger em = em_find(td->td_proc, EMUL_UNLOCKED); 107ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); 108ad2056f2SAlexander Leidinger } 109ad2056f2SAlexander Leidinger 110ad2056f2SAlexander Leidinger em->child_clear_tid = NULL; 111ad2056f2SAlexander Leidinger em->child_set_tid = NULL; 112ad2056f2SAlexander Leidinger 113ad2056f2SAlexander Leidinger /* allocate the shared struct only in clone()/fork cases 114ad2056f2SAlexander Leidinger * in the case of clone() td = calling proc and child = pid of 115ad2056f2SAlexander Leidinger * the newly created proc 116ad2056f2SAlexander Leidinger */ 117ad2056f2SAlexander Leidinger if (child != 0) { 118ad2056f2SAlexander Leidinger if (flags & CLONE_VM) { 119ad2056f2SAlexander Leidinger /* lookup the parent */ 120ad2056f2SAlexander Leidinger p_em = em_find(td->td_proc, EMUL_LOCKED); 121ad2056f2SAlexander Leidinger KASSERT(p_em != NULL, ("proc_init: parent emuldata not found for CLONE_VM\n")); 122ad2056f2SAlexander Leidinger em->shared = p_em->shared; 123ad2056f2SAlexander Leidinger em->shared->refs++; 124ad2056f2SAlexander Leidinger } else { 125ad2056f2SAlexander Leidinger /* handled earlier to avoid malloc(M_WAITOK) with rwlock held */ 126ad2056f2SAlexander Leidinger } 127ad2056f2SAlexander Leidinger } 128ad2056f2SAlexander Leidinger 129ad2056f2SAlexander Leidinger 130ad2056f2SAlexander Leidinger if (child != 0) { 131ad2056f2SAlexander Leidinger EMUL_SHARED_WLOCK(&emul_shared_lock); 132ad2056f2SAlexander Leidinger LIST_INSERT_HEAD(&em->shared->threads, em, threads); 133ad2056f2SAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 134ad2056f2SAlexander Leidinger 135ad2056f2SAlexander Leidinger p = pfind(child); 136ad2056f2SAlexander Leidinger PROC_UNLOCK(p); 137ad2056f2SAlexander Leidinger /* we might have a sleeping linux_schedtail */ 138ad2056f2SAlexander Leidinger wakeup(&p->p_emuldata); 139ad2056f2SAlexander Leidinger } else 140ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 141ad2056f2SAlexander Leidinger 142ad2056f2SAlexander Leidinger return (0); 143ad2056f2SAlexander Leidinger } 144ad2056f2SAlexander Leidinger 145ad2056f2SAlexander Leidinger void 146ad2056f2SAlexander Leidinger linux_proc_exit(void *arg __unused, struct proc *p) 147ad2056f2SAlexander Leidinger { 148ad2056f2SAlexander Leidinger struct linux_emuldata *em; 149ad2056f2SAlexander Leidinger int error; 150ad2056f2SAlexander Leidinger struct thread *td = FIRST_THREAD_IN_PROC(p); 151ad2056f2SAlexander Leidinger int *child_clear_tid; 152ad2056f2SAlexander Leidinger 153ad2056f2SAlexander Leidinger if (__predict_true(p->p_sysent != &elf_linux_sysvec)) 154ad2056f2SAlexander Leidinger return; 155ad2056f2SAlexander Leidinger 156ad2056f2SAlexander Leidinger /* find the emuldata */ 157ad2056f2SAlexander Leidinger em = em_find(p, EMUL_UNLOCKED); 158ad2056f2SAlexander Leidinger 159ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("proc_exit: emuldata not found.\n")); 160ad2056f2SAlexander Leidinger 161ad2056f2SAlexander Leidinger child_clear_tid = em->child_clear_tid; 162ad2056f2SAlexander Leidinger 163ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 164ad2056f2SAlexander Leidinger 165ad2056f2SAlexander Leidinger EMUL_SHARED_WLOCK(&emul_shared_lock); 166ad2056f2SAlexander Leidinger LIST_REMOVE(em, threads); 167ad2056f2SAlexander Leidinger 168ad2056f2SAlexander Leidinger PROC_LOCK(p); 169ad2056f2SAlexander Leidinger p->p_emuldata = NULL; 170ad2056f2SAlexander Leidinger PROC_UNLOCK(p); 171ad2056f2SAlexander Leidinger 172ad2056f2SAlexander Leidinger em->shared->refs--; 173ad2056f2SAlexander Leidinger if (em->shared->refs == 0) 174ad2056f2SAlexander Leidinger FREE(em->shared, M_LINUX); 175ad2056f2SAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 176ad2056f2SAlexander Leidinger 177ad2056f2SAlexander Leidinger if (child_clear_tid != NULL) { 178ad2056f2SAlexander Leidinger struct linux_sys_futex_args cup; 179ad2056f2SAlexander Leidinger int null = 0; 180ad2056f2SAlexander Leidinger 181ad2056f2SAlexander Leidinger error = copyout(&null, child_clear_tid, sizeof(null)); 182ad2056f2SAlexander Leidinger if (error) 183ad2056f2SAlexander Leidinger return; 184ad2056f2SAlexander Leidinger 185ad2056f2SAlexander Leidinger /* futexes stuff */ 186ad2056f2SAlexander Leidinger cup.uaddr = child_clear_tid; 187ad2056f2SAlexander Leidinger cup.op = LINUX_FUTEX_WAKE; 188ad2056f2SAlexander Leidinger cup.val = 0x7fffffff; /* Awake everyone */ 189ad2056f2SAlexander Leidinger cup.timeout = NULL; 190ad2056f2SAlexander Leidinger cup.uaddr2 = NULL; 191ad2056f2SAlexander Leidinger cup.val3 = 0; 192ad2056f2SAlexander Leidinger error = linux_sys_futex(FIRST_THREAD_IN_PROC(p), &cup); 193ad2056f2SAlexander Leidinger /* this cannot happen at the moment and if this happens 194ad2056f2SAlexander Leidinger * it probably mean there is a userspace bug 195ad2056f2SAlexander Leidinger */ 196ad2056f2SAlexander Leidinger if (error) 197ad2056f2SAlexander Leidinger printf(LMSG("futex stuff in proc_exit failed.\n")); 198ad2056f2SAlexander Leidinger } 199ad2056f2SAlexander Leidinger 200ad2056f2SAlexander Leidinger /* clean the stuff up */ 201ad2056f2SAlexander Leidinger FREE(em, M_LINUX); 202ad2056f2SAlexander Leidinger } 203ad2056f2SAlexander Leidinger 204ad2056f2SAlexander Leidinger /* This is used in a case of transition from FreeBSD binary execing to linux binary 205ad2056f2SAlexander Leidinger * in this case we create linux emuldata proc entry with the pid of the currently running 206ad2056f2SAlexander Leidinger * process. 207ad2056f2SAlexander Leidinger */ 208ad2056f2SAlexander Leidinger void linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) 209ad2056f2SAlexander Leidinger { 210ad2056f2SAlexander Leidinger if (__predict_false(imgp->sysent == &elf_linux_sysvec 211ad2056f2SAlexander Leidinger && p->p_sysent != &elf_linux_sysvec)) 212ad2056f2SAlexander Leidinger linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0); 213ad2056f2SAlexander Leidinger if (__predict_false(imgp->sysent != &elf_linux_sysvec 214ad2056f2SAlexander Leidinger && p->p_sysent == &elf_linux_sysvec)) { 215ad2056f2SAlexander Leidinger struct linux_emuldata *em; 216ad2056f2SAlexander Leidinger 217ad2056f2SAlexander Leidinger em = em_find(p, EMUL_UNLOCKED); 218ad2056f2SAlexander Leidinger 219ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("proc_exec: emuldata not found.\n")); 220ad2056f2SAlexander Leidinger 221ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 222ad2056f2SAlexander Leidinger 223ad2056f2SAlexander Leidinger EMUL_SHARED_WLOCK(&emul_shared_lock); 224ad2056f2SAlexander Leidinger LIST_REMOVE(em, threads); 225ad2056f2SAlexander Leidinger 226ad2056f2SAlexander Leidinger PROC_LOCK(p); 227ad2056f2SAlexander Leidinger p->p_emuldata = NULL; 228ad2056f2SAlexander Leidinger PROC_UNLOCK(p); 229ad2056f2SAlexander Leidinger 230ad2056f2SAlexander Leidinger em->shared->refs--; 231ad2056f2SAlexander Leidinger if (em->shared->refs == 0) 232ad2056f2SAlexander Leidinger FREE(em->shared, M_LINUX); 233ad2056f2SAlexander Leidinger EMUL_SHARED_WUNLOCK(&emul_shared_lock); 234ad2056f2SAlexander Leidinger 235ad2056f2SAlexander Leidinger FREE(em, M_LINUX); 236ad2056f2SAlexander Leidinger } 237ad2056f2SAlexander Leidinger } 238ad2056f2SAlexander Leidinger 239ad2056f2SAlexander Leidinger extern int hz; /* in subr_param.c */ 240ad2056f2SAlexander Leidinger 241ad2056f2SAlexander Leidinger void 242ad2056f2SAlexander Leidinger linux_schedtail(void *arg __unused, struct proc *p) 243ad2056f2SAlexander Leidinger { 244ad2056f2SAlexander Leidinger struct linux_emuldata *em; 245ad2056f2SAlexander Leidinger int error = 0; 246ad2056f2SAlexander Leidinger #ifdef DEBUG 247ad2056f2SAlexander Leidinger struct thread *td = FIRST_THREAD_IN_PROC(p); 248ad2056f2SAlexander Leidinger #endif 249ad2056f2SAlexander Leidinger int *child_set_tid; 250ad2056f2SAlexander Leidinger 251ad2056f2SAlexander Leidinger if (p->p_sysent != &elf_linux_sysvec) 252ad2056f2SAlexander Leidinger return; 253ad2056f2SAlexander Leidinger 254ad2056f2SAlexander Leidinger retry: 255ad2056f2SAlexander Leidinger /* find the emuldata */ 256ad2056f2SAlexander Leidinger em = em_find(p, EMUL_UNLOCKED); 257ad2056f2SAlexander Leidinger 258ad2056f2SAlexander Leidinger if (em == NULL) { 259ad2056f2SAlexander Leidinger /* We might have been called before proc_init for this process so 260ad2056f2SAlexander Leidinger * tsleep and be woken up by it. We use p->p_emuldata for this 261ad2056f2SAlexander Leidinger */ 262ad2056f2SAlexander Leidinger 263ad2056f2SAlexander Leidinger error = tsleep(&p->p_emuldata, PLOCK, "linux_schedtail", hz); 264ad2056f2SAlexander Leidinger if (error == 0) 265ad2056f2SAlexander Leidinger goto retry; 266ad2056f2SAlexander Leidinger panic("no emuldata found for userreting process.\n"); 267ad2056f2SAlexander Leidinger } 268ad2056f2SAlexander Leidinger child_set_tid = em->child_set_tid; 269ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 270ad2056f2SAlexander Leidinger 271ad2056f2SAlexander Leidinger if (child_set_tid != NULL) 272ad2056f2SAlexander Leidinger error = copyout(&p->p_pid, (int *) child_set_tid, sizeof(p->p_pid)); 273ad2056f2SAlexander Leidinger 274ad2056f2SAlexander Leidinger return; 275ad2056f2SAlexander Leidinger } 276ad2056f2SAlexander Leidinger 277ad2056f2SAlexander Leidinger int 278ad2056f2SAlexander Leidinger linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) 279ad2056f2SAlexander Leidinger { 280ad2056f2SAlexander Leidinger struct linux_emuldata *em; 281ad2056f2SAlexander Leidinger 282ad2056f2SAlexander Leidinger #ifdef DEBUG 283ad2056f2SAlexander Leidinger if (ldebug(set_tid_address)) 284ad2056f2SAlexander Leidinger printf(ARGS(set_tid_address, "%p"), args->tidptr); 285ad2056f2SAlexander Leidinger #endif 286ad2056f2SAlexander Leidinger 287ad2056f2SAlexander Leidinger /* find the emuldata */ 288ad2056f2SAlexander Leidinger em = em_find(td->td_proc, EMUL_UNLOCKED); 289ad2056f2SAlexander Leidinger 290ad2056f2SAlexander Leidinger KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); 291ad2056f2SAlexander Leidinger 292ad2056f2SAlexander Leidinger em->child_clear_tid = args->tidptr; 293ad2056f2SAlexander Leidinger td->td_retval[0] = td->td_proc->p_pid; 294ad2056f2SAlexander Leidinger 295ad2056f2SAlexander Leidinger EMUL_UNLOCK(&emul_lock); 296ad2056f2SAlexander Leidinger return 0; 297ad2056f2SAlexander Leidinger } 298