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/irix/irix_prctl.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: irix_prctl.c,v 1.48 2008/07/02 19:49:58 rmind Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2001-2002 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Emmanuel Dreyfus.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: irix_prctl.c,v 1.48 2008/07/02 19:49:58 rmind Exp $");
   34 
   35 #include <sys/errno.h>
   36 #include <sys/types.h>
   37 #include <sys/param.h>
   38 #include <sys/signal.h>
   39 #include <sys/signalvar.h>
   40 #include <sys/systm.h>
   41 #include <sys/exec.h>
   42 #include <sys/malloc.h>
   43 #include <sys/pool.h>
   44 #include <sys/rwlock.h>
   45 #include <sys/filedesc.h>
   46 #include <sys/vnode.h>
   47 #include <sys/resourcevar.h>
   48 #include <sys/kauth.h>
   49 
   50 #include <uvm/uvm_extern.h>
   51 #include <uvm/uvm_map.h>
   52 
   53 #include <machine/regnum.h>
   54 #include <machine/vmparam.h>
   55 
   56 #include <compat/svr4/svr4_types.h>
   57 
   58 #include <compat/irix/irix_types.h>
   59 #include <compat/irix/irix_exec.h>
   60 #include <compat/irix/irix_prctl.h>
   61 #include <compat/irix/irix_signal.h>
   62 #include <compat/irix/irix_syscallargs.h>
   63 
   64 struct irix_sproc_child_args {
   65         struct proc **isc_proc;
   66         void *isc_entry;
   67         void *isc_arg;
   68         size_t isc_len;
   69         int isc_inh;
   70         struct lwp *isc_parent_lwp;
   71         struct irix_share_group *isc_share_group;
   72         int isc_child_done;
   73 };
   74 static void irix_sproc_child(struct irix_sproc_child_args *);
   75 static int irix_sproc(void *, unsigned int, void *, void *, size_t,
   76     pid_t, struct lwp *, register_t *);
   77 static struct irix_shared_regions_rec *irix_isrr_create(vaddr_t,
   78     vsize_t, int);
   79 #ifdef DEBUG_IRIX
   80 static void irix_isrr_debug(struct proc *);
   81 #endif
   82 static void irix_isrr_cleanup(struct proc *);
   83 
   84 int
   85 irix_sys_prctl(struct lwp *l, const struct irix_sys_prctl_args *uap, register_t *retval)
   86 {
   87         /* {
   88                 syscallarg(unsigned) option;
   89                 syscallarg(void *) arg1;
   90         } */
   91         struct proc *p = l->l_proc;
   92         unsigned int option = SCARG(uap, option);
   93 
   94 #ifdef DEBUG_IRIX
   95         printf("irix_sys_prctl(): option = %d\n", option);
   96 #endif
   97 
   98         switch(option) {
   99         case IRIX_PR_GETSHMASK: {       /* Get shared resources */
  100                 struct proc *p2;
  101                 int shmask = 0;
  102                 struct irix_emuldata *ied;
  103 
  104                 p2 = pfind((pid_t)SCARG(uap, arg1));
  105 
  106                 if (p2 == p || SCARG(uap, arg1) == 0) {
  107                         /* XXX return our own shmask */
  108                         return 0;
  109                 }
  110 
  111                 if (p2 == NULL)
  112                         return EINVAL;
  113 
  114                 ied = (struct irix_emuldata *)p->p_emuldata;
  115                 if (ied->ied_shareaddr)
  116                         shmask |= IRIX_PR_SADDR;
  117                 if (p->p_fd == p2->p_fd)
  118                         shmask |= IRIX_PR_SFDS;
  119                 if (p->p_cwdi == p2->p_cwdi)
  120                         shmask |= (IRIX_PR_SDIR|IRIX_PR_SUMASK);
  121 
  122                 *retval = (register_t)shmask;
  123                 return 0;
  124                 break;
  125         }
  126 
  127         case IRIX_PR_LASTSHEXIT:        /* "Last sproc exit" */
  128                 /* We no nothing */
  129                 break;
  130 
  131         case IRIX_PR_GETNSHARE: {       /* Number of sproc share group memb.*/
  132                 struct irix_emuldata *ied;
  133                 struct irix_emuldata *iedp;
  134                 struct irix_share_group *isg;
  135                 int count;
  136 
  137                 ied = (struct irix_emuldata *)p->p_emuldata;
  138                 if ((isg = ied->ied_share_group) == NULL) {
  139                         *retval = 0;
  140                         return 0;
  141                 }
  142 
  143                 count = 0;
  144                 rw_enter(&isg->isg_lock, RW_READER);
  145                 LIST_FOREACH(iedp, &isg->isg_head, ied_sglist)
  146                         count++;
  147                 rw_exit(&isg->isg_lock);
  148 
  149                 *retval = count;
  150                 return 0;
  151                 break;
  152         }
  153 
  154         case IRIX_PR_TERMCHILD: {       /* Get SIGHUP when parent's exit */
  155                 struct irix_emuldata *ied;
  156 
  157                 ied = (struct irix_emuldata *)(p->p_emuldata);
  158                 ied->ied_termchild = 1;
  159                 break;
  160         }
  161 
  162         case IRIX_PR_ISBLOCKED: {       /* Is process blocked? */
  163                 pid_t pid = (pid_t)SCARG(uap, arg1);
  164                 struct irix_emuldata *ied;
  165                 struct proc *target;
  166 
  167                 if (pid == 0)
  168                         pid = p->p_pid;
  169 
  170                 if ((target = pfind(pid)) == NULL)
  171                         return ESRCH;
  172 
  173                 if (irix_check_exec(target) == 0)
  174                         return 0;
  175 
  176                 if (kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
  177                     target, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL,
  178                     NULL) != 0)
  179                         return EPERM;
  180 
  181                 ied = (struct irix_emuldata *)(target->p_emuldata);
  182                 *retval = (ied->ied_procblk_count < 0);
  183                 return 0;
  184                 break;
  185         }
  186 
  187         default:
  188                 printf("Warning: call to unimplemented prctl() command %d\n",
  189                     option);
  190                 return EINVAL;
  191                 break;
  192         }
  193         return 0;
  194 }
  195 
  196 
  197 int
  198 irix_sys_pidsprocsp(struct lwp *l, const struct irix_sys_pidsprocsp_args *uap, register_t *retval)
  199 {
  200         /* {
  201                 syscallarg(void *) entry;
  202                 syscallarg(unsigned) inh;
  203                 syscallarg(void *) arg;
  204                 syscallarg(void *) sp;
  205                 syscallarg(irix_size_t) len;
  206                 syscallarg(irix_pid_t) pid;
  207         } */
  208 
  209         /* pid is ignored for now */
  210         printf("Warning: unsupported pid argument to IRIX sproc\n");
  211 
  212         return irix_sproc(SCARG(uap, entry), SCARG(uap, inh), SCARG(uap, arg),
  213             SCARG(uap, sp), SCARG(uap, len), SCARG(uap, pid), l, retval);
  214 }
  215 
  216 int
  217 irix_sys_sprocsp(struct lwp *l, const struct irix_sys_sprocsp_args *uap, register_t *retval)
  218 {
  219         /* {
  220                 syscallarg(void *) entry;
  221                 syscallarg(unsigned) inh;
  222                 syscallarg(void *) arg;
  223                 syscallarg(void *) sp;
  224                 syscallarg(irix_size_t) len;
  225         } */
  226 
  227         return irix_sproc(SCARG(uap, entry), SCARG(uap, inh), SCARG(uap, arg),
  228             SCARG(uap, sp), SCARG(uap, len), 0, l, retval);
  229 }
  230 
  231 int
  232 irix_sys_sproc(struct lwp *l, const struct irix_sys_sproc_args *uap, register_t *retval)
  233 {
  234         /* {
  235                 syscallarg(void *) entry;
  236                 syscallarg(unsigned) inh;
  237                 syscallarg(void *) arg;
  238         } */
  239         struct proc *p = l->l_proc;
  240 
  241         return irix_sproc(SCARG(uap, entry), SCARG(uap, inh), SCARG(uap, arg),
  242             NULL, p->p_rlimit[RLIMIT_STACK].rlim_cur, 0, l, retval);
  243 }
  244 
  245 
  246 static int
  247 irix_sproc(void *entry, unsigned int inh, void *arg, void *sp, size_t len, pid_t pid, struct lwp *l, register_t *retval)
  248 {
  249         struct proc *p = l->l_proc;
  250         int bsd_flags = 0;
  251         struct exec_vmcmd vmc;
  252         int error;
  253         struct proc *p2;
  254         struct irix_sproc_child_args *isc;
  255         struct irix_emuldata *ied;
  256         struct irix_emuldata *iedp;
  257         struct irix_share_group *isg = NULL;
  258         segsz_t stacksize;
  259 
  260 #ifdef DEBUG_IRIX
  261         printf("irix_sproc(): entry = %p, inh = %x, arg = %p, sp = 0x%08lx, len = 0x%08lx, pid = %d\n", entry, inh, arg, (u_long)sp, (u_long)len, pid);
  262 #endif
  263 
  264         if (len == 0)
  265                 return EINVAL;
  266 
  267         if (inh & IRIX_PR_SFDS)
  268                 bsd_flags |= FORK_SHAREFILES;
  269         if (inh & IRIX_PR_SUMASK && inh & IRIX_PR_SDIR) {
  270                 bsd_flags |= FORK_SHARECWD;
  271                 /* Forget them so that we don't get warning below */
  272                 inh &= ~(IRIX_PR_SUMASK|IRIX_PR_SDIR);
  273         }
  274         /* We know how to do PR_SUMASK and PR_SDIR together only */
  275         if (inh & IRIX_PR_SUMASK)
  276                 printf("Warning: unimplemented IRIX sproc flag PR_SUMASK\n");
  277         if (inh & IRIX_PR_SDIR)
  278                 printf("Warning: unimplemented IRIX sproc flag PR_SDIR\n");
  279         if (inh & IRIX_PR_SULIMIT)
  280                 bsd_flags |= FORK_SHARELIMIT;
  281 
  282         /*
  283          * If relevant, initialize the share group structure
  284          */
  285         ied = (struct irix_emuldata *)(p->p_emuldata);
  286         if (ied->ied_share_group == NULL) {
  287                 isg = malloc(sizeof(struct irix_share_group),
  288                     M_EMULDATA, M_WAITOK);
  289                 rw_init(&isg->isg_lock);
  290                 isg->isg_refcount = 0;
  291 
  292                 rw_enter(&isg->isg_lock, RW_WRITER);
  293                 LIST_INIT(&isg->isg_head);
  294                 LIST_INSERT_HEAD(&isg->isg_head, ied, ied_sglist);
  295                 isg->isg_refcount++;
  296                 rw_exit(&isg->isg_lock);
  297 
  298                 ied->ied_share_group = isg;
  299         }
  300 
  301         /*
  302          * Setting up child stack
  303          */
  304         if (inh & IRIX_PR_SADDR) {
  305                 if (sp == NULL) {
  306                         /*
  307                          * All share group  members have vm_maxsaddr set
  308                          * to the bottom of the lowest stack in address space,
  309                          * therefore we map the new stack there.
  310                          */
  311                         sp = p->p_vmspace->vm_maxsaddr;
  312 
  313                         /* Compute new stacks's bottom address */
  314                         sp = (void *)trunc_page((u_long)sp - len);
  315                 }
  316 
  317                 /* Now map the new stack */
  318                 bzero(&vmc, sizeof(vmc));
  319                 vmc.ev_addr = trunc_page((u_long)sp);
  320                 vmc.ev_len = round_page(len);
  321                 vmc.ev_prot = UVM_PROT_RWX;
  322                 vmc.ev_flags = UVM_FLAG_COPYONW|UVM_FLAG_FIXED|UVM_FLAG_OVERLAY;
  323                 vmc.ev_proc = vmcmd_map_zero;
  324 #ifdef DEBUG_IRIX
  325                 printf("irix_sproc(): new stack addr=0x%08lx, len=0x%08lx\n",
  326                     (u_long)sp, (u_long)len);
  327 #endif
  328                 /* Normally it cannot be NULL since we just initialized it */
  329                 if ((isg = ied->ied_share_group) == NULL)
  330                         panic("irix_sproc: NULL ied->ied_share_group");
  331 
  332                 IRIX_VM_SYNC(p, error = (*vmc.ev_proc)(l, &vmc));
  333                 if (error)
  334                         return error;
  335 
  336                 /* Update stack parameters for the share group members */
  337                 ied = (struct irix_emuldata *)p->p_emuldata;
  338                 stacksize = ((char *)p->p_vmspace->vm_minsaddr - (char *)sp)
  339                     / PAGE_SIZE;
  340 
  341 
  342                 rw_enter(&isg->isg_lock, RW_WRITER);
  343                 LIST_FOREACH(iedp, &isg->isg_head, ied_sglist) {
  344                         iedp->ied_p->p_vmspace->vm_maxsaddr = (void *)sp;
  345                         iedp->ied_p->p_vmspace->vm_ssize = stacksize;
  346                 }
  347                 rw_exit(&isg->isg_lock);
  348         }
  349 
  350         /*
  351          * Arguments for irix_sproc_child()
  352          * This will be freed by the child.
  353          */
  354         isc = malloc(sizeof(*isc), M_TEMP, M_WAITOK);
  355         isc->isc_proc = &p2;
  356         isc->isc_entry = entry;
  357         isc->isc_arg = arg;
  358         isc->isc_len = len;
  359         isc->isc_inh = inh;
  360         isc->isc_parent_lwp = l;
  361         isc->isc_share_group = isg;
  362         isc->isc_child_done = 0;
  363 
  364         if (inh & IRIX_PR_SADDR) {
  365                 ied->ied_shareaddr = 1;
  366         }
  367 
  368         if ((error = fork1(l, bsd_flags, SIGCHLD, (void *)sp, len,
  369             (void *)irix_sproc_child, (void *)isc, retval, &p2)) != 0)
  370                 return error;
  371 
  372         /*
  373          * The child needs the parent to stay alive until it has
  374          * copied a few things from it. We sleep whatever happen
  375          * until the child is done.
  376          */
  377         while (!isc->isc_child_done)
  378                 (void)tsleep(&isc->isc_child_done, PZERO, "sproc", 0);
  379         free(isc, M_TEMP);
  380 
  381         retval[0] = (register_t)p2->p_pid;
  382         retval[1] = 0;
  383 
  384         return 0;
  385 }
  386 
  387 static void
  388 irix_sproc_child(struct irix_sproc_child_args *isc)
  389 {
  390         struct proc *p2 = *isc->isc_proc;
  391         struct lwp *l2 = curlwp;
  392         int inh = isc->isc_inh;
  393         struct lwp *lparent = isc->isc_parent_lwp;
  394         struct proc *parent = lparent->l_proc;
  395         struct frame *tf = (struct frame *)l2->l_md.md_regs;
  396         struct frame *ptf = (struct frame *)lparent->l_md.md_regs;
  397         kauth_cred_t pc;
  398         struct irix_emuldata *ied;
  399         struct irix_emuldata *parent_ied;
  400 
  401 #ifdef DEBUG_IRIX
  402         printf("irix_sproc_child()\n");
  403 #endif
  404         /*
  405          * Handle shared VM space. The process private arena is not shared
  406          */
  407         if (inh & IRIX_PR_SADDR) {
  408                 int error;
  409                 vaddr_t minp, maxp;
  410                 vsize_t len;
  411                 struct irix_shared_regions_rec *isrr;
  412 
  413                 /*
  414                  * First, unmap the whole address space
  415                  */
  416                 minp = vm_map_min(&p2->p_vmspace->vm_map);
  417                 maxp = vm_map_max(&p2->p_vmspace->vm_map);
  418                 uvm_unmap(&p2->p_vmspace->vm_map, minp, maxp);
  419 
  420                 /*
  421                  * Now, copy the mapping from the parent for shared regions
  422                  */
  423                 parent_ied = (struct irix_emuldata *)parent->p_emuldata;
  424                 LIST_FOREACH(isrr, &parent_ied->ied_shared_regions, isrr_list) {
  425                         minp = isrr->isrr_start;
  426                         len = isrr->isrr_len;
  427                         maxp = minp + len;
  428                         /* If this is a private region, skip */
  429                         if (isrr->isrr_shared == IRIX_ISRR_PRIVATE)
  430                                 continue;
  431 
  432                         /* Copy the new mapping from the parent */
  433                         error = uvm_map_extract(&parent->p_vmspace->vm_map,
  434                             minp, len, &p2->p_vmspace->vm_map, &minp, 0);
  435                         if (error != 0) {
  436 #ifdef DEBUG_IRIX
  437                                 printf("irix_sproc_child(): error %d\n", error);
  438 #endif
  439                                 isc->isc_child_done = 1;
  440                                 wakeup(&isc->isc_child_done);
  441                                 mutex_enter(proc_lock);
  442                                 killproc(p2,
  443                                     "failed to initialize share group VM");
  444                                 mutex_exit(proc_lock);
  445                         }
  446                 }
  447 
  448                 /* Map and initialize the process private arena (unshared) */
  449                 error = irix_prda_init(p2);
  450                 if (error != 0) {
  451                         isc->isc_child_done = 1;
  452                         wakeup(&isc->isc_child_done);
  453                         mutex_enter(proc_lock);
  454                         killproc(p2, "failed to initialize the PRDA");
  455                         mutex_exit(proc_lock);
  456                 }
  457         }
  458 
  459         /*
  460          * Handle shared process UID/GID
  461          */
  462         if (inh & IRIX_PR_SID) {
  463                 pc = p2->p_cred;
  464                 kauth_cred_hold(parent->p_cred);
  465                 p2->p_cred = parent->p_cred;
  466                 kauth_cred_free(pc);
  467         }
  468 
  469         /*
  470          * Setup PC to return to the child entry point
  471          */
  472         tf->f_regs[_R_PC] = (unsigned long)isc->isc_entry;
  473         tf->f_regs[_R_RA] = 0;
  474 
  475         /*
  476          * Setup child arguments
  477          */
  478         tf->f_regs[_R_A0] = (unsigned long)isc->isc_arg;
  479         tf->f_regs[_R_A1] = 0;
  480         tf->f_regs[_R_A2] = 0;
  481         tf->f_regs[_R_A3] = 0;
  482         if (ptf->f_regs[_R_S3] == (unsigned long)isc->isc_len) {
  483                 tf->f_regs[_R_S0] = ptf->f_regs[_R_S0];
  484                 tf->f_regs[_R_S1] = ptf->f_regs[_R_S1];
  485                 tf->f_regs[_R_S2] = ptf->f_regs[_R_S2];
  486                 tf->f_regs[_R_S3] = ptf->f_regs[_R_S3];
  487         }
  488 
  489         /*
  490          * Join the share group
  491          */
  492         ied = (struct irix_emuldata *)(p2->p_emuldata);
  493         parent_ied = (struct irix_emuldata *)(parent->p_emuldata);
  494         ied->ied_share_group = parent_ied->ied_share_group;
  495 
  496         rw_enter(&ied->ied_share_group->isg_lock, RW_WRITER);
  497         LIST_INSERT_HEAD(&ied->ied_share_group->isg_head, ied, ied_sglist);
  498         ied->ied_share_group->isg_refcount++;
  499         rw_exit(&ied->ied_share_group->isg_lock);
  500 
  501         if (inh & IRIX_PR_SADDR)
  502                 ied->ied_shareaddr = 1;
  503 
  504         /*
  505          * wakeup the parent as it can now die without
  506          * causing a panic in the child.
  507          */
  508         isc->isc_child_done = 1;
  509         wakeup(&isc->isc_child_done);
  510 
  511         /*
  512          * Return to userland for a newly created process
  513          */
  514         child_return((void *)l2);
  515         return;
  516 }
  517 
  518 int
  519 irix_sys_procblk(struct lwp *l, const struct irix_sys_procblk_args *uap, register_t *retval)
  520 {
  521         /* {
  522                 syscallarg(int) cmd;
  523                 syscallarg(pid_t) pid;
  524                 syscallarg(int) count;
  525         } */
  526         int cmd = SCARG(uap, cmd);
  527         struct irix_emuldata *ied;
  528         struct irix_emuldata *iedp;
  529         struct irix_share_group *isg;
  530         struct proc *target;
  531         int oldcount;
  532         struct lwp *ied_lwp;
  533         int error, last_error;
  534         struct irix_sys_procblk_args cup;
  535 
  536         /* Find the process */
  537         if ((target = pfind(SCARG(uap, pid))) == NULL)
  538                 return ESRCH;
  539 
  540         /* May we stop it? */
  541         /* XXX-elad: Is hardcoding SIGSTOP here correct? */
  542         if (kauth_authorize_process(l->l_cred, KAUTH_PROCESS_SIGNAL, target,
  543             KAUTH_ARG(SIGSTOP), NULL, NULL) != 0)
  544                 return EPERM;
  545 
  546         /* Is it an IRIX process? */
  547         if (irix_check_exec(target) == 0)
  548                 return EPERM;
  549 
  550         ied = (struct irix_emuldata *)(target->p_emuldata);
  551         oldcount = ied->ied_procblk_count;
  552 
  553         switch (cmd) {
  554         case IRIX_PROCBLK_BLOCK:
  555                 ied->ied_procblk_count--;
  556                 break;
  557 
  558         case IRIX_PROCBLK_UNBLOCK:
  559                 ied->ied_procblk_count++;
  560                 break;
  561 
  562         case IRIX_PROCBLK_COUNT:
  563                 if (SCARG(uap, count) > IRIX_PR_MAXBLOCKCNT ||
  564                     SCARG(uap, count) < IRIX_PR_MINBLOCKCNT)
  565                         return EINVAL;
  566                 ied->ied_procblk_count = SCARG(uap, count);
  567                 break;
  568 
  569         case IRIX_PROCBLK_BLOCKALL:
  570         case IRIX_PROCBLK_UNBLOCKALL:
  571         case IRIX_PROCBLK_COUNTALL:
  572                 SCARG(&cup, cmd) = cmd -IRIX_PROCBLK_ONLYONE;
  573                 SCARG(&cup, count) = SCARG(uap, count);
  574                 last_error = 0;
  575 
  576                 /*
  577                  * If the process does not belong to a
  578                  * share group, do it just for the process
  579                  */
  580                 if ((isg = ied->ied_share_group) == NULL) {
  581                         SCARG(&cup, pid) = SCARG(uap, pid);
  582                         return irix_sys_procblk(l, &cup, retval);
  583                 }
  584 
  585                 rw_enter(&isg->isg_lock, RW_READER);
  586                 LIST_FOREACH(iedp, &isg->isg_head, ied_sglist) {
  587                         struct proc *p;
  588                         /* Recall procblk for this process */
  589                         p = iedp->ied_p;
  590                         SCARG(&cup, pid) = p->p_pid;
  591                         ied_lwp = LIST_FIRST(&p->p_lwps);
  592                         KASSERT(ied_lwp != NULL);
  593                         error = irix_sys_procblk(ied_lwp, &cup, retval);
  594                         if (error != 0)
  595                                 last_error = error;
  596                 }
  597                 rw_exit(&isg->isg_lock);
  598 
  599                 return last_error;
  600                 break;
  601         default:
  602                 printf("Warning: unimplemented IRIX procblk command %d\n", cmd);
  603                 return EINVAL;
  604                 break;
  605         }
  606 
  607         /*
  608          * We emulate the process block/unblock using SIGSTOP and SIGCONT
  609          * signals. This is not very accurate, since on IRIX theses way
  610          * of blocking a process are completely separated.
  611          */
  612         if (oldcount >= 0 && ied->ied_procblk_count < 0) /* blocked */
  613                 psignal(target, SIGSTOP);
  614 
  615         if (oldcount < 0 && ied->ied_procblk_count >= 0) /* unblocked */
  616                 psignal(target, SIGCONT);
  617 
  618         return 0;
  619 }
  620 
  621 int
  622 irix_prda_init(struct proc *p)
  623 {
  624         int error;
  625         struct exec_vmcmd evc;
  626         struct irix_prda *ip;
  627         struct irix_prda_sys ips;
  628         struct lwp *l;
  629 
  630         bzero(&evc, sizeof(evc));
  631         evc.ev_addr = (u_long)IRIX_PRDA;
  632         evc.ev_len = sizeof(struct irix_prda);
  633         evc.ev_prot = UVM_PROT_RW;
  634         evc.ev_proc = *vmcmd_map_zero;
  635 
  636         /* XXXSMP */
  637         l = LIST_FIRST(&p->p_lwps);
  638         KASSERT(l != NULL);
  639 
  640         if ((error = (*evc.ev_proc)(l, &evc)) != 0)
  641                 return error;
  642 
  643         ip = (struct irix_prda *)IRIX_PRDA;
  644         bzero(&ips, sizeof(ips));
  645 
  646         ips.t_pid = p->p_pid;
  647         /*
  648          * The PRDA ID must be unique for a PRDA. IRIX uses a small
  649          * integer, but we don't know how it is chosen. The PID
  650          * should be unique enough to get the work done.
  651          */
  652         ips.t_prid = p->p_pid;
  653 
  654         error = copyout(&ips, (void *)&ip->sys_prda.prda_sys, sizeof(ips));
  655         if (error)
  656                 return error;
  657 
  658         /* Remeber the PRDA is private */
  659         irix_isrr_insert((vaddr_t)IRIX_PRDA, sizeof(ips), IRIX_ISRR_PRIVATE, p);
  660 
  661         return 0;
  662 }
  663 
  664 int
  665 irix_vm_fault(struct proc *p, vaddr_t vaddr, vm_prot_t access_type)
  666 {
  667         int error;
  668         struct irix_emuldata *ied;
  669         struct vm_map *map;
  670 
  671         ied = (struct irix_emuldata *)p->p_emuldata;
  672         map = &p->p_vmspace->vm_map;
  673 
  674         if (ied->ied_share_group == NULL || ied->ied_shareaddr == 0)
  675                 return uvm_fault(map, vaddr, access_type);
  676 
  677         /* share group version */
  678         rw_enter(&ied->ied_share_group->isg_lock, RW_WRITER);
  679         error = uvm_fault(map, vaddr, access_type);
  680         irix_vm_sync(p);
  681         rw_exit(&ied->ied_share_group->isg_lock);
  682 
  683         return error;
  684 }
  685 
  686 /*
  687  * Propagate changes to address space to other members of the share group
  688  */
  689 void
  690 irix_vm_sync(struct proc *p)
  691 {
  692         struct proc *pp;
  693         struct irix_emuldata *iedp;
  694         struct irix_emuldata *ied = (struct irix_emuldata *)p->p_emuldata;
  695         struct irix_shared_regions_rec *isrr;
  696         vaddr_t minp;
  697         vaddr_t maxp;
  698         vsize_t len;
  699         int error;
  700 
  701         LIST_FOREACH(iedp, &ied->ied_share_group->isg_head, ied_sglist) {
  702                 if (iedp->ied_shareaddr != 1 || iedp->ied_p == p)
  703                         continue;
  704 
  705                 pp = iedp->ied_p;
  706 
  707                 error = 0;
  708                 /* for each region in the target process ... */
  709                 LIST_FOREACH(isrr, &iedp->ied_shared_regions, isrr_list) {
  710                         /* skip regions private to the target process */
  711                         if (isrr->isrr_shared == IRIX_ISRR_PRIVATE)
  712                                 continue;
  713 
  714                         /*
  715                          * XXX We should also skip regions private to the
  716                          * original process...
  717                          */
  718 
  719                         /* The region is shared */
  720                         minp = isrr->isrr_start;
  721                         len = isrr->isrr_len;
  722                         maxp = minp + len;
  723 
  724                         /* Drop the region */
  725                         uvm_unmap(&pp->p_vmspace->vm_map, minp, maxp);
  726 
  727                         /* Clone it from the parent */
  728                         error = uvm_map_extract(&p->p_vmspace->vm_map,
  729                             minp, len, &pp->p_vmspace->vm_map, &minp, 0);
  730 
  731                         if (error)
  732                                 break;
  733                 }
  734 
  735                 if (error) {
  736                         mutex_enter(proc_lock);
  737                         killproc(pp, "failed to keep share group VM in sync");
  738                         mutex_exit(proc_lock);
  739                 }
  740         }
  741 
  742         return;
  743 }
  744 
  745 static struct irix_shared_regions_rec *
  746 irix_isrr_create(vaddr_t start, vsize_t len, int shared)
  747 {
  748         struct irix_shared_regions_rec *new_isrr;
  749 
  750         new_isrr = malloc(sizeof(struct irix_shared_regions_rec),
  751             M_EMULDATA, M_WAITOK);
  752         new_isrr->isrr_start = start;
  753         new_isrr->isrr_len = len;
  754         new_isrr->isrr_shared = shared;
  755 
  756         return new_isrr;
  757 }
  758 
  759 /*
  760  * Insert a record for a new region in the list. The new region may be
  761  * overlaping or be included in an existing region.
  762  */
  763 void
  764 irix_isrr_insert(vaddr_t start, vsize_t len, int shared, struct proc *p)
  765 {
  766         struct irix_emuldata *ied = (struct irix_emuldata *)p->p_emuldata;
  767         struct irix_shared_regions_rec *isrr;
  768         struct irix_shared_regions_rec *new_isrr;
  769         vaddr_t end, cur_start, cur_end;
  770         int cur_shared;
  771 
  772         start = trunc_page(start);
  773         len = round_page(len);
  774         end = start + len;
  775 
  776         new_isrr = irix_isrr_create(start, len, shared);
  777 
  778         /* Do we need to insert the new region at the begining of the list? */
  779         if (LIST_EMPTY(&ied->ied_shared_regions) ||
  780             LIST_FIRST(&ied->ied_shared_regions)->isrr_start > start) {
  781                 LIST_INSERT_HEAD(&ied->ied_shared_regions, new_isrr, isrr_list);
  782         } else {
  783                 /* Find the place where to insert it */
  784                 LIST_FOREACH(isrr, &ied->ied_shared_regions, isrr_list) {
  785                         cur_start = isrr->isrr_start;
  786                         cur_end = isrr->isrr_start + isrr->isrr_len;
  787                         cur_shared = isrr->isrr_shared;
  788 
  789                         /*
  790                          * if there is no intersection between inserted
  791                          * and current region: skip to next region
  792                          */
  793                         if (cur_end <= start)
  794                                 continue;
  795 
  796                         /*
  797                          * if new region is included into the current
  798                          * region. Right-crop the current region,
  799                          * insert a new one, and insert a new region
  800                          * for the end of the split region
  801                          */
  802                         if (cur_end > end && cur_start < start) {
  803                                 isrr->isrr_len = start - isrr->isrr_start;
  804                                 LIST_INSERT_AFTER(isrr, new_isrr, isrr_list);
  805                                 isrr = new_isrr;
  806 
  807                                 new_isrr = irix_isrr_create(end,
  808                                     cur_end - end, cur_shared);
  809                                 LIST_INSERT_AFTER(isrr, new_isrr, isrr_list);
  810 
  811                                 /* Nothing more to do, exit now */
  812 #ifdef DEBUG_IRIX
  813                                 irix_isrr_debug(p);
  814 #endif
  815                                 irix_isrr_cleanup(p);
  816 #ifdef DEBUG_IRIX
  817                                 irix_isrr_debug(p);
  818 #endif
  819                                 return;
  820                         }
  821 
  822                         /*
  823                          * if inserted block overlap some part
  824                          * of current region: right-crop current region
  825                          * and insert the new region
  826                          */
  827                         if (start < cur_end) {
  828                                 isrr->isrr_len = start - cur_start;
  829                                 LIST_INSERT_AFTER(isrr, new_isrr, isrr_list);
  830 
  831                                 /* exit the FOREACH loop */
  832                                 break;
  833                         }
  834                 }
  835         }
  836 
  837         /*
  838          * At this point, we inserted the new region (new_isrr) but
  839          * it may be overlaping with next regions, so we need to clean
  840          * this up and remove or crop next regions
  841          */
  842         LIST_FOREACH(isrr, &ied->ied_shared_regions, isrr_list) {
  843                 cur_start = isrr->isrr_start;
  844                 cur_end = isrr->isrr_start + isrr->isrr_len;
  845 
  846                 /* skip until we get beyond new_isrr */
  847                 if (cur_start <= start)
  848                         continue;
  849 
  850                 if (end >= cur_end) { /* overlap */
  851                         LIST_REMOVE(isrr, isrr_list);
  852                         free(isrr, M_EMULDATA);
  853                         /* isrr is now invalid */
  854                         isrr = new_isrr;
  855                         continue;
  856                 }
  857 
  858                 /*
  859                  * Here end < cur_end, therefore we need to
  860                  * right-crop the current region
  861                  */
  862                  isrr->isrr_start = end;
  863                  isrr->isrr_len = cur_end - end;
  864                  break;
  865         }
  866 #ifdef DEBUG_IRIX
  867         irix_isrr_debug(p);
  868 #endif
  869         irix_isrr_cleanup(p);
  870 #ifdef DEBUG_IRIX
  871         irix_isrr_debug(p);
  872 #endif
  873         return;
  874 }
  875 
  876 /*
  877  * Cleanup the region list by
  878  * (1) removing regions with length 0, and
  879  * (2) merging contiguous regions with the same status
  880  */
  881 static void
  882 irix_isrr_cleanup(struct proc *p)
  883 {
  884         struct irix_emuldata *ied = (struct irix_emuldata *)p->p_emuldata;
  885         struct irix_shared_regions_rec *isrr;
  886         struct irix_shared_regions_rec *new_isrr;
  887 
  888         isrr = LIST_FIRST(&ied->ied_shared_regions);
  889         do {
  890                 new_isrr = LIST_NEXT(isrr, isrr_list);
  891 
  892                 if (isrr->isrr_len == 0) {
  893                         LIST_REMOVE(isrr, isrr_list);
  894                         free(isrr, M_EMULDATA);
  895                         isrr = new_isrr;
  896                         if (isrr == NULL)
  897                                 break;
  898                 }
  899 
  900                 if (new_isrr == NULL)
  901                         break;
  902 
  903                 if (isrr->isrr_shared == new_isrr->isrr_shared) {
  904                         isrr->isrr_len += new_isrr->isrr_len;
  905                         new_isrr->isrr_len = 0;
  906                 }
  907 
  908                 isrr = new_isrr;
  909         } while (1);
  910 
  911         return;
  912 }
  913 
  914 
  915 #ifdef DEBUG_IRIX
  916 static void
  917 irix_isrr_debug(struct proc *p)
  918 {
  919         struct irix_emuldata *ied = (struct irix_emuldata *)p->p_emuldata;
  920         struct irix_shared_regions_rec *isrr;
  921 
  922         printf("isrr for pid %d\n", p->p_pid);
  923         LIST_FOREACH(isrr, &ied->ied_shared_regions, isrr_list) {
  924                 printf("  addr = %p, len = %p, shared = %d\n",
  925                     (void *)isrr->isrr_start,
  926                     (void *)isrr->isrr_len,
  927                     isrr->isrr_shared);
  928         }
  929 }
  930 #endif /* DEBUG_IRIX */

Cache object: 71ebd0ec584b1b32784720e87c0e4c19


[ 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.