1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #include <sys/types.h>
  30 #include <sys/systm.h>
  31 #include <sys/errno.h>
  32 #include <sys/segments.h>
  33 #include <sys/archsystm.h>
  34 #include <sys/proc.h>
  35 #include <sys/sysi86.h>
  36 #include <sys/cmn_err.h>
  37 #include <sys/lx_ldt.h>
  38 
  39 /*
  40  * Read the ldt_info structure in from the Linux app, convert it to an ssd
  41  * structure, and then call setdscr() to do all the heavy lifting.
  42  */
  43 static int
  44 write_ldt(void *data, ulong_t count)
  45 {
  46         user_desc_t usd;
  47         struct ssd ssd;
  48         struct ldt_info ldt_inf;
  49         proc_t *pp = curthread->t_procp;
  50         int err;
  51 
  52         if (count != sizeof (ldt_inf))
  53                 return (set_errno(EINVAL));
  54 
  55         if (copyin(data, &ldt_inf, sizeof (ldt_inf)))
  56                 return (set_errno(EFAULT));
  57 
  58         if (ldt_inf.entry_number >= MAXNLDT)
  59                 return (set_errno(EINVAL));
  60 
  61         LDT_INFO_TO_DESC(&ldt_inf, &usd);
  62         usd_to_ssd(&usd, &ssd, SEL_LDT(ldt_inf.entry_number));
  63 
  64         /*
  65          * Get everyone into a safe state before changing the LDT.
  66          */
  67         if (!holdlwps(SHOLDFORK1))
  68                 return (set_errno(EINTR));
  69 
  70         err = setdscr(&ssd);
  71 
  72         /*
  73          * Release the hounds!
  74          */
  75         mutex_enter(&pp->p_lock);
  76         continuelwps(pp);
  77         mutex_exit(&pp->p_lock);
  78 
  79         return (err ? set_errno(err) : 0);
  80 }
  81 
  82 static int
  83 read_ldt(void *uptr, ulong_t count)
  84 {
  85         proc_t *pp = curproc;
  86         int bytes;
  87 
  88         if (pp->p_ldt == NULL)
  89                 return (0);
  90 
  91         bytes = (pp->p_ldtlimit + 1) * sizeof (user_desc_t);
  92         if (bytes > count)
  93                 bytes = count;
  94 
  95         if (copyout(pp->p_ldt, uptr, bytes))
  96                 return (set_errno(EFAULT));
  97 
  98         return (bytes);
  99 }
 100 
 101 long
 102 lx_modify_ldt(int op, void *data, ulong_t count)
 103 {
 104         int rval;
 105 
 106         switch (op) {
 107         case 0:
 108                 rval = read_ldt(data, count);
 109                 break;
 110 
 111         case 1:
 112                 rval = write_ldt(data, count);
 113                 break;
 114 
 115         default:
 116                 rval = set_errno(ENOSYS);
 117                 break;
 118         }
 119 
 120         return (rval);
 121 }