root/arch/i386/i386/sys_machdep.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. i386_print_ldt
  2. i386_get_ldt
  3. i386_set_ldt
  4. i386_iopl
  5. i386_get_ioperm
  6. i386_set_ioperm
  7. sys_sysarch

    1 /*      $OpenBSD: sys_machdep.c,v 1.26 2006/09/19 11:06:33 jsg Exp $    */
    2 /*      $NetBSD: sys_machdep.c,v 1.28 1996/05/03 19:42:29 christos Exp $        */
    3 
    4 /*-
    5  * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
    6  * Copyright (c) 1990 The Regents of the University of California.
    7  * All rights reserved.
    8  *
    9  * This code is derived from software contributed to Berkeley by
   10  * William Jolitz.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)sys_machdep.c       5.5 (Berkeley) 1/19/91
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/ioctl.h>
   42 #include <sys/file.h>
   43 #include <sys/time.h>
   44 #include <sys/proc.h>
   45 #include <sys/signalvar.h>
   46 #include <sys/user.h>
   47 #include <sys/uio.h>
   48 #include <sys/kernel.h>
   49 #include <sys/mtio.h>
   50 #include <sys/buf.h>
   51 #include <sys/signal.h>
   52 #include <sys/malloc.h>
   53 
   54 #include <sys/mount.h>
   55 #include <sys/syscallargs.h>
   56 
   57 #include <uvm/uvm_extern.h>
   58 
   59 #include <machine/cpu.h>
   60 #include <machine/cpufunc.h>
   61 #include <machine/gdt.h>
   62 #include <machine/psl.h>
   63 #include <machine/reg.h>
   64 #include <machine/sysarch.h>
   65 
   66 #ifdef VM86
   67 #include <machine/vm86.h>
   68 #endif
   69 
   70 extern struct vm_map *kernel_map;
   71 
   72 int i386_iopl(struct proc *, void *, register_t *);
   73 int i386_get_ioperm(struct proc *, void *, register_t *);
   74 int i386_set_ioperm(struct proc *, void *, register_t *);
   75 
   76 #ifdef USER_LDT
   77 
   78 #ifdef LDT_DEBUG
   79 static void i386_print_ldt(int, const struct segment_descriptor *);
   80 
   81 static void
   82 i386_print_ldt(int i, const struct segment_descriptor *d)
   83 {
   84         printf("[%d] lolimit=0x%x, lobase=0x%x, type=%u, dpl=%u, p=%u, "
   85             "hilimit=0x%x, xx=%x, def32=%u, gran=%u, hibase=0x%x\n",
   86             i, d->sd_lolimit, d->sd_lobase, d->sd_type, d->sd_dpl, d->sd_p,
   87             d->sd_hilimit, d->sd_xx, d->sd_def32, d->sd_gran, d->sd_hibase);
   88 }
   89 #endif
   90 
   91 int
   92 i386_get_ldt(struct proc *p, void *args, register_t *retval)
   93 {
   94         int error;
   95         pmap_t pmap = p->p_vmspace->vm_map.pmap;
   96         int nldt, num;
   97         union descriptor *lp, *cp;
   98         struct i386_get_ldt_args ua;
   99 
  100         if (user_ldt_enable == 0)
  101                 return (ENOSYS);
  102 
  103         if ((error = copyin(args, &ua, sizeof(ua))) != 0)
  104                 return (error);
  105 
  106 #ifdef  LDT_DEBUG
  107         printf("i386_get_ldt: start=%d num=%d descs=%p\n", ua.start,
  108             ua.num, ua.desc);
  109 #endif
  110 
  111         if (ua.start < 0 || ua.num < 0 || ua.start > 8192 || ua.num > 8192 ||
  112             ua.start + ua.num > 8192)
  113                 return (EINVAL);
  114 
  115         cp = malloc(ua.num * sizeof(union descriptor), M_TEMP, M_WAITOK);
  116         if (cp == NULL)
  117                 return ENOMEM;
  118 
  119         simple_lock(&pmap->pm_lock);
  120 
  121         if (pmap->pm_flags & PMF_USER_LDT) {
  122                 nldt = pmap->pm_ldt_len;
  123                 lp = pmap->pm_ldt;
  124         } else {
  125                 nldt = NLDT;
  126                 lp = ldt;
  127         }
  128 
  129         if (ua.start > nldt) {
  130                 simple_unlock(&pmap->pm_lock);
  131                 free(cp, M_TEMP);
  132                 return (EINVAL);
  133         }
  134 
  135         lp += ua.start;
  136         num = min(ua.num, nldt - ua.start);
  137 #ifdef LDT_DEBUG
  138         {
  139                 int i;
  140                 for (i = 0; i < num; i++)
  141                         i386_print_ldt(i, &lp[i].sd);
  142         }
  143 #endif
  144 
  145         memcpy(cp, lp, num * sizeof(union descriptor));
  146         simple_unlock(&pmap->pm_lock);
  147 
  148         error = copyout(cp, ua.desc, num * sizeof(union descriptor));
  149         if (error == 0)
  150                 *retval = num;
  151 
  152         free(cp, M_TEMP);
  153         return (error);
  154 }
  155 
  156 int
  157 i386_set_ldt(struct proc *p, void *args, register_t *retval)
  158 {
  159         int error, i, n;
  160         struct pcb *pcb = &p->p_addr->u_pcb;
  161         pmap_t pmap = p->p_vmspace->vm_map.pmap;
  162         struct i386_set_ldt_args ua;
  163         union descriptor *descv;
  164         size_t old_len, new_len, ldt_len;
  165         union descriptor *old_ldt, *new_ldt;
  166 
  167         if (user_ldt_enable == 0)
  168                 return (ENOSYS);
  169 
  170         if ((error = copyin(args, &ua, sizeof(ua))) != 0)
  171                 return (error);
  172 
  173         if (ua.start < 0 || ua.num < 0 || ua.start > 8192 || ua.num > 8192 ||
  174             ua.start + ua.num > 8192)
  175                 return (EINVAL);
  176 
  177         descv = malloc(sizeof (*descv) * ua.num, M_TEMP, M_NOWAIT);
  178         if (descv == NULL)
  179                 return (ENOMEM);
  180 
  181         if ((error = copyin(ua.desc, descv, sizeof (*descv) * ua.num)) != 0)
  182                 goto out;
  183 
  184         /* Check descriptors for access violations. */
  185         for (i = 0; i < ua.num; i++) {
  186                 union descriptor *desc = &descv[i];
  187 
  188                 switch (desc->sd.sd_type) {
  189                 case SDT_SYSNULL:
  190                         desc->sd.sd_p = 0;
  191                         break;
  192                 case SDT_SYS286CGT:
  193                 case SDT_SYS386CGT:
  194                         /*
  195                          * Only allow call gates targeting a segment
  196                          * in the LDT or a user segment in the fixed
  197                          * part of the gdt.  Segments in the LDT are
  198                          * constrained (below) to be user segments.
  199                          */
  200                         if (desc->gd.gd_p != 0 &&
  201                             !ISLDT(desc->gd.gd_selector) &&
  202                             ((IDXSEL(desc->gd.gd_selector) >= NGDT) ||
  203                              (gdt[IDXSEL(desc->gd.gd_selector)].sd.sd_dpl !=
  204                                  SEL_UPL))) {
  205                                 error = EACCES;
  206                                 goto out;
  207                         }
  208                         break;
  209                 case SDT_MEMEC:
  210                 case SDT_MEMEAC:
  211                 case SDT_MEMERC:
  212                 case SDT_MEMERAC:
  213                         /* Must be "present" if executable and conforming. */
  214                         if (desc->sd.sd_p == 0) {
  215                                 error = EACCES;
  216                                 goto out;
  217                         }
  218                         break;
  219                 case SDT_MEMRO:
  220                 case SDT_MEMROA:
  221                 case SDT_MEMRW:
  222                 case SDT_MEMRWA:
  223                 case SDT_MEMROD:
  224                 case SDT_MEMRODA:
  225                 case SDT_MEMRWD:
  226                 case SDT_MEMRWDA:
  227                 case SDT_MEME:
  228                 case SDT_MEMEA:
  229                 case SDT_MEMER:
  230                 case SDT_MEMERA:
  231                         break;
  232                 default:
  233                         /*
  234                          * Make sure that unknown descriptor types are
  235                          * not marked present.
  236                          */
  237                         if (desc->sd.sd_p != 0) {
  238                                 error = EACCES;
  239                                 goto out;
  240                         }
  241                         break;
  242                 }
  243 
  244                 if (desc->sd.sd_p != 0) {
  245                         /* Only user (ring-3) descriptors may be present. */
  246                         if (desc->sd.sd_dpl != SEL_UPL) {
  247                                 error = EACCES;
  248                                 goto out;
  249                         }
  250                 }
  251         }
  252 
  253         /* allocate user ldt */
  254         simple_lock(&pmap->pm_lock);
  255         if (pmap->pm_ldt == 0 || (ua.start + ua.num) > pmap->pm_ldt_len) {
  256                 if (pmap->pm_flags & PMF_USER_LDT)
  257                         ldt_len = pmap->pm_ldt_len;
  258                 else
  259                         ldt_len = 512;
  260                 while ((ua.start + ua.num) > ldt_len)
  261                         ldt_len *= 2;
  262                 new_len = ldt_len * sizeof(union descriptor);
  263 
  264                 simple_unlock(&pmap->pm_lock);
  265                 new_ldt = (union descriptor *)uvm_km_alloc(kernel_map,
  266                     new_len);
  267                 simple_lock(&pmap->pm_lock);
  268 
  269                 if (pmap->pm_ldt != NULL && ldt_len <= pmap->pm_ldt_len) {
  270                         /*
  271                          * Another thread (re)allocated the LDT to
  272                          * sufficient size while we were blocked in
  273                          * uvm_km_alloc. Oh well. The new entries
  274                          * will quite probably not be right, but
  275                          * hey.. not our problem if user applications
  276                          * have race conditions like that.
  277                          */
  278                         uvm_km_free(kernel_map, (vaddr_t)new_ldt, new_len);
  279                         goto copy;
  280                 }
  281 
  282                 old_ldt = pmap->pm_ldt;
  283 
  284                 if (old_ldt != NULL) {
  285                         old_len = pmap->pm_ldt_len * sizeof(union descriptor);
  286                 } else {
  287                         old_len = NLDT * sizeof(union descriptor);
  288                         old_ldt = ldt;
  289                 }
  290 
  291                 memcpy(new_ldt, old_ldt, old_len);
  292                 memset((caddr_t)new_ldt + old_len, 0, new_len - old_len);
  293 
  294                 if (old_ldt != ldt)
  295                         uvm_km_free(kernel_map, (vaddr_t)old_ldt, old_len);
  296 
  297                 pmap->pm_ldt = new_ldt;
  298                 pmap->pm_ldt_len = ldt_len;
  299 
  300                 if (pmap->pm_flags & PMF_USER_LDT)
  301                         ldt_free(pmap);
  302                 else
  303                         pmap->pm_flags |= PMF_USER_LDT;
  304                 ldt_alloc(pmap, new_ldt, new_len);
  305                 pcb->pcb_ldt_sel = pmap->pm_ldt_sel;
  306                 if (pcb == curpcb)
  307                         lldt(pcb->pcb_ldt_sel);
  308 
  309         }
  310 copy:
  311         /* Now actually replace the descriptors. */
  312         for (i = 0, n = ua.start; i < ua.num; i++, n++)
  313                 pmap->pm_ldt[n] = descv[i];
  314 
  315         simple_unlock(&pmap->pm_lock);
  316 
  317         *retval = ua.start;
  318 
  319 out:
  320         free(descv, M_TEMP);
  321         return (error);
  322 }
  323 #endif  /* USER_LDT */
  324 
  325 #ifdef APERTURE
  326 extern int allowaperture;
  327 #endif
  328 
  329 int
  330 i386_iopl(struct proc *p, void *args, register_t *retval)
  331 {
  332         int error;
  333         struct trapframe *tf = p->p_md.md_regs;
  334         struct i386_iopl_args ua;
  335 
  336         if ((error = suser(p, 0)) != 0)
  337                 return error;
  338 #ifdef APERTURE
  339         if (!allowaperture && securelevel > 0)
  340                 return EPERM;
  341 #else
  342         if (securelevel > 0)
  343                 return EPERM;
  344 #endif
  345 
  346         if ((error = copyin(args, &ua, sizeof(ua))) != 0)
  347                 return error;
  348 
  349         if (ua.iopl)
  350                 tf->tf_eflags |= PSL_IOPL;
  351         else
  352                 tf->tf_eflags &= ~PSL_IOPL;
  353 
  354         return 0;
  355 }
  356 
  357 int
  358 i386_get_ioperm(struct proc *p, void *args, register_t *retval)
  359 {
  360         int error;
  361         struct pcb *pcb = &p->p_addr->u_pcb;
  362         struct i386_get_ioperm_args ua;
  363 
  364         if ((error = copyin(args, &ua, sizeof(ua))) != 0)
  365                 return (error);
  366 
  367         return copyout(pcb->pcb_iomap, ua.iomap, sizeof(pcb->pcb_iomap));
  368 }
  369 
  370 int
  371 i386_set_ioperm(struct proc *p, void *args, register_t *retval)
  372 {
  373         int error;
  374         struct pcb *pcb = &p->p_addr->u_pcb;
  375         struct i386_set_ioperm_args ua;
  376 
  377         if ((error = suser(p, 0)) != 0)
  378                 return error;
  379 
  380 #ifdef APERTURE
  381         if (!allowaperture && securelevel > 0)
  382                 return EPERM;
  383 #else
  384         if (securelevel > 0)
  385                 return EPERM;
  386 #endif
  387         if ((error = copyin(args, &ua, sizeof(ua))) != 0)
  388                 return (error);
  389 
  390         return copyin(ua.iomap, pcb->pcb_iomap, sizeof(pcb->pcb_iomap));
  391 }
  392 
  393 int
  394 sys_sysarch(struct proc *p, void *v, register_t *retval)
  395 {
  396         struct sys_sysarch_args /* {
  397                 syscallarg(int) op;
  398                 syscallarg(void *) parms;
  399         } */ *uap = v;
  400         int error = 0;
  401 
  402         switch(SCARG(uap, op)) {
  403 #ifdef  USER_LDT
  404         case I386_GET_LDT:
  405                 error = i386_get_ldt(p, SCARG(uap, parms), retval);
  406                 break;
  407 
  408         case I386_SET_LDT:
  409                 error = i386_set_ldt(p, SCARG(uap, parms), retval);
  410                 break;
  411 #endif
  412 
  413         case I386_IOPL:
  414                 error = i386_iopl(p, SCARG(uap, parms), retval);
  415                 break;
  416 
  417         case I386_GET_IOPERM:
  418                 error = i386_get_ioperm(p, SCARG(uap, parms), retval);
  419                 break;
  420 
  421         case I386_SET_IOPERM:
  422                 error = i386_set_ioperm(p, SCARG(uap, parms), retval);
  423                 break;
  424 
  425 #ifdef VM86
  426         case I386_VM86:
  427                 error = i386_vm86(p, SCARG(uap, parms), retval);
  428                 break;
  429 #endif
  430 
  431         default:
  432                 error = EINVAL;
  433                 break;
  434         }
  435         return (error);
  436 }

/* [<][>][^][v][top][bottom][index][help] */