The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linux/common/linux_exec.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: linux_exec.c,v 1.108 2008/10/28 11:42:30 jmcneill Exp $        */
    2 
    3 /*-
    4  * Copyright (c) 1994, 1995, 1998, 2000, 2007, 2008 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  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.108 2008/10/28 11:42:30 jmcneill Exp $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>
   39 #include <sys/proc.h>
   40 #include <sys/malloc.h>
   41 #include <sys/namei.h>
   42 #include <sys/vnode.h>
   43 #include <sys/mount.h>
   44 #include <sys/exec.h>
   45 #include <sys/exec_elf.h>
   46 
   47 #include <sys/mman.h>
   48 #include <sys/syscallargs.h>
   49 
   50 #include <sys/ptrace.h> /* For proc_reparent() */
   51 
   52 #include <uvm/uvm_extern.h>
   53 
   54 #include <sys/cpu.h>
   55 #include <machine/reg.h>
   56 
   57 #include <compat/linux/common/linux_types.h>
   58 #include <compat/linux/common/linux_signal.h>
   59 #include <compat/linux/common/linux_util.h>
   60 #include <compat/linux/common/linux_sched.h>
   61 #include <compat/linux/common/linux_machdep.h>
   62 #include <compat/linux/common/linux_exec.h>
   63 #include <compat/linux/common/linux_futex.h>
   64 #include <compat/linux/common/linux_ipc.h>
   65 #include <compat/linux/common/linux_sem.h>
   66 
   67 #include <compat/linux/linux_syscallargs.h>
   68 #include <compat/linux/linux_syscall.h>
   69 #include <compat/linux/common/linux_misc.h>
   70 #include <compat/linux/common/linux_errno.h>
   71 #include <compat/linux/common/linux_emuldata.h>
   72 
   73 extern struct sysent linux_sysent[];
   74 extern const char * const linux_syscallnames[];
   75 extern char linux_sigcode[], linux_esigcode[];
   76 
   77 static void linux_e_proc_exec(struct proc *, struct exec_package *);
   78 static void linux_e_proc_fork(struct proc *, struct proc *, int);
   79 static void linux_e_proc_exit(struct proc *);
   80 static void linux_e_proc_init(struct proc *, struct proc *, int);
   81 
   82 #ifdef LINUX_NPTL
   83 void linux_userret(void);
   84 #endif
   85 
   86 /*
   87  * Emulation switch.
   88  */
   89 
   90 struct uvm_object *emul_linux_object;
   91 
   92 const struct emul emul_linux = {
   93         "linux",
   94         "/emul/linux",
   95 #ifndef __HAVE_MINIMAL_EMUL
   96         0,
   97         (const int *)native_to_linux_errno,
   98         LINUX_SYS_syscall,
   99         LINUX_SYS_NSYSENT,
  100 #endif
  101         linux_sysent,
  102         linux_syscallnames,
  103         linux_sendsig,
  104         linux_trapsignal,
  105         NULL,
  106         linux_sigcode,
  107         linux_esigcode,
  108         &emul_linux_object,
  109         linux_setregs,
  110         linux_e_proc_exec,
  111         linux_e_proc_fork,
  112         linux_e_proc_exit,
  113         NULL,
  114         NULL,
  115 #ifdef __HAVE_SYSCALL_INTERN
  116         linux_syscall_intern,
  117 #else
  118 #error Implement __HAVE_SYSCALL_INTERN for this platform
  119 #endif
  120         NULL,
  121         NULL,
  122 
  123         uvm_default_mapaddr,
  124 
  125         linux_usertrap,
  126         NULL,           /* e_sa */
  127         0,
  128         NULL,           /* e_startlwp */
  129 };
  130 
  131 static void
  132 linux_e_proc_init(p, parent, forkflags)
  133         struct proc *p, *parent;
  134         int forkflags;
  135 {
  136         struct linux_emuldata *e = p->p_emuldata;
  137         struct linux_emuldata_shared *s;
  138         struct linux_emuldata *ep = NULL;
  139 
  140         if (!e) {
  141                 /* allocate new Linux emuldata */
  142                 MALLOC(e, void *, sizeof(struct linux_emuldata),
  143                         M_EMULDATA, M_WAITOK);
  144         } else  {
  145                 mutex_enter(proc_lock);
  146                 e->s->refs--;
  147                 if (e->s->refs == 0)
  148                         FREE(e->s, M_EMULDATA);
  149                 mutex_exit(proc_lock);
  150         }
  151 
  152         memset(e, '\0', sizeof(struct linux_emuldata));
  153 
  154         e->proc = p;
  155         e->robust_futexes = NULL;
  156 
  157         if (parent)
  158                 ep = parent->p_emuldata;
  159 
  160         if (forkflags & FORK_SHAREVM) {
  161                 mutex_enter(proc_lock);
  162 #ifdef DIAGNOSTIC
  163                 if (ep == NULL) {
  164                         killproc(p, "FORK_SHAREVM while emuldata is NULL\n");
  165                         mutex_exit(proc_lock);
  166                         FREE(e, M_EMULDATA);
  167                         return;
  168                 }
  169 #endif
  170                 s = ep->s;
  171                 s->refs++;
  172         } else {
  173                 struct vmspace *vm;
  174 
  175                 MALLOC(s, void *, sizeof(struct linux_emuldata_shared),
  176                         M_EMULDATA, M_WAITOK);
  177                 s->refs = 1;
  178 
  179                 /*
  180                  * Set the process idea of the break to the real value.
  181                  * For fork, we use parent's vmspace since our's
  182                  * is not setup at the time of this call and is going
  183                  * to be copy of parent's anyway. For exec, just
  184                  * use our own vmspace.
  185                  */
  186                 vm = (parent) ? parent->p_vmspace : p->p_vmspace;
  187                 s->p_break = (char *)vm->vm_daddr + ctob(vm->vm_dsize);
  188 
  189                 /*
  190                  * Linux threads are emulated as NetBSD processes (not lwp)
  191                  * We use native PID for Linux TID. The Linux TID is the
  192                  * PID of the first process in the group. It is stored
  193                  * here
  194                  */
  195                 s->group_pid = p->p_pid;
  196 
  197                 /*
  198                  * Initialize the list of threads in the group
  199                  */
  200                 LIST_INIT(&s->threads);
  201 
  202                 s->xstat = 0;
  203                 s->flags = 0;
  204                 mutex_enter(proc_lock);
  205         }
  206 
  207         e->s = s;
  208 
  209         /*
  210          * Add this thread in the group thread list
  211          */
  212         LIST_INSERT_HEAD(&s->threads, e, threads);
  213 
  214 #ifdef LINUX_NPTL
  215         if (ep != NULL) {
  216                 e->parent_tidptr = ep->parent_tidptr;
  217                 e->child_tidptr = ep->child_tidptr;
  218                 e->clone_flags = ep->clone_flags;
  219         }
  220 #endif /* LINUX_NPTL */
  221 
  222         mutex_exit(proc_lock);
  223         p->p_emuldata = e;
  224 }
  225 
  226 /*
  227  * Allocate new per-process structures. Called when executing Linux
  228  * process. We can reuse the old emuldata - if it's not null,
  229  * the executed process is of same emulation as original forked one.
  230  */
  231 static void
  232 linux_e_proc_exec(struct proc *p, struct exec_package *epp)
  233 {
  234 
  235         /* exec, use our vmspace */
  236         linux_e_proc_init(p, NULL, 0);
  237 }
  238 
  239 /*
  240  * Emulation per-process exit hook.
  241  */
  242 static void
  243 linux_e_proc_exit(struct proc *p)
  244 {
  245         struct linux_emuldata *e = p->p_emuldata;
  246 
  247 #ifdef LINUX_NPTL
  248         linux_nptl_proc_exit(p);
  249         release_futexes(p);
  250 #endif
  251 
  252         /* Remove the thread for the group thread list */
  253         mutex_enter(proc_lock);
  254         LIST_REMOVE(e, threads);
  255 
  256         /* free Linux emuldata and set the pointer to null */
  257         e->s->refs--;
  258         if (e->s->refs == 0)
  259                 FREE(e->s, M_EMULDATA);
  260         p->p_emuldata = NULL;
  261         mutex_exit(proc_lock);
  262         FREE(e, M_EMULDATA);
  263 }
  264 
  265 /*
  266  * Emulation fork hook.
  267  */
  268 static void
  269 linux_e_proc_fork(p, parent, forkflags)
  270         struct proc *p, *parent;
  271         int forkflags;
  272 {
  273 
  274         /*
  275          * The new process might share some vmspace-related stuff
  276          * with parent, depending on fork flags (CLONE_VM et.al).
  277          * Force allocation of new base emuldata, and share the
  278          * VM-related parts only if necessary.
  279          */
  280         p->p_emuldata = NULL;
  281         linux_e_proc_init(p, parent, forkflags);
  282 
  283 #ifdef LINUX_NPTL
  284         linux_nptl_proc_fork(p, parent, linux_userret);
  285 #endif
  286 
  287         return;
  288 }
  289 
  290 #ifdef LINUX_NPTL
  291 void
  292 linux_userret(void)
  293 {
  294         struct lwp *l = curlwp;
  295         struct proc *p = l->l_proc;
  296         struct linux_emuldata *led = p->p_emuldata;
  297         int error;
  298 
  299         /* LINUX_CLONE_CHILD_SETTID: copy child's TID to child's memory  */
  300         if (led->clone_flags & LINUX_CLONE_CHILD_SETTID) {
  301                 if ((error = copyout(&l->l_proc->p_pid,
  302                     led->child_tidptr,  sizeof(l->l_proc->p_pid))) != 0)
  303                         printf("linux_userret: LINUX_CLONE_CHILD_SETTID "
  304                             "failed (led->child_tidptr = %p, p->p_pid = %d)\n",
  305                             led->child_tidptr, p->p_pid);
  306         }
  307 
  308         /* LINUX_CLONE_SETTLS: allocate a new TLS */
  309         if (led->clone_flags & LINUX_CLONE_SETTLS) {
  310                 if (linux_set_newtls(l, linux_get_newtls(l)) != 0)
  311                         printf("linux_userret: linux_set_tls failed");
  312         }
  313 
  314         return; 
  315 }
  316 
  317 void
  318 linux_nptl_proc_exit(struct proc *p)
  319 {
  320         struct linux_emuldata *e = p->p_emuldata;
  321 
  322         mutex_enter(proc_lock);
  323 
  324         /* 
  325          * Check if we are a thread group leader victim of another 
  326          * thread doing exit_group(). If we are, change the exit code. 
  327          */
  328         if ((e->s->group_pid == p->p_pid) &&
  329             (e->s->flags & LINUX_LES_INEXITGROUP)) {
  330                 p->p_xstat = e->s->xstat;
  331         }
  332 
  333         /*
  334          * Members of the thread groups others than the leader should
  335          * exit quietely: no zombie stage, no signal. We do that by
  336          * reparenting to init. init will collect us and nobody will 
  337          * notice what happened.
  338          */
  339 #ifdef DEBUG_LINUX
  340         printf("%s:%d e->s->group_pid = %d, p->p_pid = %d, flags = 0x%x\n", 
  341             __func__, __LINE__, e->s->group_pid, p->p_pid, e->s->flags);
  342 #endif
  343         if ((e->s->group_pid != p->p_pid) &&
  344             (e->clone_flags & LINUX_CLONE_THREAD)) {
  345                 proc_reparent(p, initproc);     
  346                 cv_broadcast(&initproc->p_waitcv);
  347         }
  348 
  349         mutex_exit(proc_lock);
  350 
  351         /* Emulate LINUX_CLONE_CHILD_CLEARTID */
  352         if (e->clear_tid != NULL) {
  353                 int error;
  354                 int null = 0;
  355                 struct linux_sys_futex_args cup;
  356                 register_t retval;
  357 
  358                 error = copyout(&null, e->clear_tid, sizeof(null));
  359 #ifdef DEBUG_LINUX
  360                 if (error != 0)
  361                         printf("%s: cannot clear TID\n", __func__);
  362 #endif
  363 
  364                 SCARG(&cup, uaddr) = e->clear_tid;
  365                 SCARG(&cup, op) = LINUX_FUTEX_WAKE;
  366                 SCARG(&cup, val) = 0x7fffffff; /* Awake everyone */
  367                 SCARG(&cup, timeout) = NULL;
  368                 SCARG(&cup, uaddr2) = NULL;
  369                 SCARG(&cup, val3) = 0;
  370                 if ((error = linux_sys_futex(curlwp, &cup, &retval)) != 0)
  371                         printf("%s: linux_sys_futex failed\n", __func__);
  372         }
  373 
  374         return;
  375 }
  376 
  377 void
  378 linux_nptl_proc_fork(p, parent, luserret)
  379         struct proc *p;
  380         struct proc *parent;
  381         void (*luserret)(void);
  382 {
  383         struct linux_emuldata *e = p->p_emuldata;
  384 
  385         /* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */
  386         if (e->clone_flags & LINUX_CLONE_CHILD_CLEARTID)
  387                 e->clear_tid = e->child_tidptr;
  388 
  389         /* LINUX_CLONE_PARENT_SETTID: set child's TID in parent's memory */
  390         if (e->clone_flags & LINUX_CLONE_PARENT_SETTID) {
  391                 if (copyout_proc(parent, &p->p_pid,
  392                     e->parent_tidptr,  sizeof(p->p_pid)) != 0)
  393                         printf("%s: LINUX_CLONE_PARENT_SETTID "
  394                             "failed (e->parent_tidptr = %p, "
  395                             "parent->p_pid = %d, p->p_pid = %d)\n",
  396                             __func__, e->parent_tidptr, 
  397                             parent->p_pid, p->p_pid);
  398         }
  399 
  400         /* 
  401          * CLONE_CHILD_SETTID and LINUX_CLONE_SETTLS require child's VM
  402          * setup to be completed, we postpone them until userret time.
  403          */
  404         if (e->clone_flags &
  405             (LINUX_CLONE_CHILD_CLEARTID | LINUX_CLONE_SETTLS))
  406                 p->p_userret = luserret;
  407 
  408         return;
  409 }
  410 
  411 void
  412 linux_nptl_proc_init(struct proc *p, struct proc *parent)
  413 {
  414         struct linux_emuldata *e = p->p_emuldata;
  415         struct linux_emuldata *ep;
  416 
  417         if ((parent != NULL) && (parent->p_emuldata != NULL)) {
  418                 ep = parent->p_emuldata;
  419 
  420                 e->parent_tidptr = ep->parent_tidptr;
  421                 e->child_tidptr = ep->child_tidptr;
  422                 e->clone_flags = ep->clone_flags;
  423         }
  424 
  425         return;
  426 }
  427 #endif /* LINUX_NPTL */

Cache object: bea2e1928e8c86e48c913278d50df42c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.