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/i386/i386/sys_machdep.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 /*-
    2  * Copyright (c) 1990 The Regents of the University of California.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by the University of
   16  *      California, Berkeley and its contributors.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      from: @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91
   34  * $FreeBSD: src/sys/i386/i386/sys_machdep.c,v 1.17.2.2 1999/09/05 08:11:18 peter Exp $
   35  *
   36  */
   37 
   38 #include "opt_user_ldt.h"
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/sysproto.h>
   42 #include <sys/proc.h>
   43 
   44 #include <vm/vm.h>
   45 #include <vm/vm_param.h>
   46 #include <vm/vm_prot.h>
   47 #include <vm/lock.h>
   48 #include <vm/pmap.h>
   49 #include <vm/vm_map.h>
   50 #include <vm/vm_extern.h>
   51 
   52 #include <sys/user.h>
   53 
   54 #include <machine/cpu.h>
   55 #include <machine/sysarch.h>
   56 
   57 #include <vm/vm_kern.h>         /* for kernel_map */
   58 
   59 #define MAX_LD 8192
   60 #define LD_PER_PAGE 512
   61 #define NEW_MAX_LD(num)  ((num + LD_PER_PAGE) & ~(LD_PER_PAGE-1))
   62 #define SIZE_FROM_LARGEST_LD(num) (NEW_MAX_LD(num) << 3)
   63 
   64 
   65 
   66 void set_user_ldt       __P((struct pcb *pcb));
   67 #ifdef USER_LDT
   68 static int i386_get_ldt __P((struct proc *, char *, int *));
   69 static int i386_set_ldt __P((struct proc *, char *, int *));
   70 #endif
   71 
   72 #ifndef _SYS_SYSPROTO_H_
   73 struct sysarch_args {
   74         int op;
   75         char *parms;
   76 };
   77 #endif
   78 
   79 int
   80 sysarch(p, uap, retval)
   81         struct proc *p;
   82         register struct sysarch_args *uap;
   83         int *retval;
   84 {
   85         int error = 0;
   86 
   87         switch(uap->op) {
   88 #ifdef  USER_LDT
   89         case I386_GET_LDT:
   90                 error = i386_get_ldt(p, uap->parms, retval);
   91                 break;
   92 
   93         case I386_SET_LDT:
   94                 error = i386_set_ldt(p, uap->parms, retval);
   95                 break;
   96 #endif
   97         default:
   98                 error = EINVAL;
   99                 break;
  100         }
  101         return(error);
  102 }
  103 
  104 #ifdef USER_LDT
  105 /*
  106  * Update the GDT entry pointing to the LDT to point to the LDT of the
  107  * current process.
  108  */   
  109 void
  110 set_user_ldt(struct pcb *pcb)
  111 {
  112         gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)pcb->pcb_ldt;
  113         gdt_segs[GUSERLDT_SEL].ssd_limit = (pcb->pcb_ldt_len * sizeof(union descriptor)) - 1;
  114         ssdtosd(&gdt_segs[GUSERLDT_SEL], &gdt[GUSERLDT_SEL].sd);
  115         lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
  116         currentldt = GSEL(GUSERLDT_SEL, SEL_KPL);
  117 }
  118 
  119 struct i386_get_ldt_args {
  120         int start;
  121         union descriptor *desc;
  122         int num;
  123 };
  124 
  125 static int
  126 i386_get_ldt(p, args, retval)
  127         struct proc *p;
  128         char *args;
  129         int *retval;
  130 {
  131         int error = 0;
  132         struct pcb *pcb = &p->p_addr->u_pcb;
  133         int nldt, num;
  134         union descriptor *lp;
  135         int s;
  136         struct i386_get_ldt_args ua;
  137         struct i386_get_ldt_args *uap = &ua;
  138 
  139         if ((error = copyin(args, uap, sizeof(struct i386_get_ldt_args))) < 0)
  140                 return(error);
  141 
  142 #ifdef  DEBUG
  143         printf("i386_get_ldt: start=%d num=%d descs=%x\n", uap->start,
  144                 uap->num, uap->desc);
  145 #endif
  146 
  147         /* verify range of LDTs exist */
  148         if ((uap->start < 0) || (uap->num <= 0))
  149                 return(EINVAL);
  150 
  151         s = splhigh();
  152 
  153         if (pcb->pcb_ldt) {
  154                 nldt = pcb->pcb_ldt_len;
  155                 num = min(uap->num, nldt);
  156                 lp = &((union descriptor *)(pcb->pcb_ldt))[uap->start];
  157         } else {
  158                 nldt = sizeof(ldt)/sizeof(ldt[0]);
  159                 num = min(uap->num, nldt);
  160                 lp = &ldt[uap->start];
  161         }
  162         if (uap->start > nldt) {
  163                 splx(s);
  164                 return(EINVAL);
  165         }
  166 
  167         error = copyout(lp, uap->desc, num * sizeof(union descriptor));
  168         if (!error)
  169                 *retval = num;
  170 
  171         splx(s);
  172         return(error);
  173 }
  174 
  175 struct i386_set_ldt_args {
  176         int start;
  177         union descriptor *desc;
  178         int num;
  179 };
  180 
  181 static int
  182 i386_set_ldt(p, args, retval)
  183         struct proc *p;
  184         char *args;
  185         int *retval;
  186 {
  187         int error = 0, i, n;
  188         int largest_ld;
  189         struct pcb *pcb = &p->p_addr->u_pcb;
  190         int s;
  191         struct i386_set_ldt_args ua, *uap;
  192 
  193         if ((error = copyin(args, &ua, sizeof(struct i386_set_ldt_args))) < 0)
  194                 return(error);
  195 
  196         uap = &ua;
  197 
  198 #ifdef  DEBUG
  199         printf("i386_set_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc);
  200 #endif
  201 
  202         /* verify range of descriptors to modify */
  203         if ((uap->start < 0) || (uap->start >= MAX_LD) || (uap->num < 0) ||
  204                 (uap->num > MAX_LD))
  205         {
  206                 return(EINVAL);
  207         }
  208         largest_ld = uap->start + uap->num - 1;
  209         if (largest_ld >= MAX_LD)
  210                 return(EINVAL);
  211   
  212         /* allocate user ldt */
  213         if (!pcb->pcb_ldt || (largest_ld >= pcb->pcb_ldt_len)) {
  214                 union descriptor *new_ldt = (union descriptor *)kmem_alloc(
  215                         kernel_map, SIZE_FROM_LARGEST_LD(largest_ld));
  216                 if (new_ldt == NULL) {
  217                         return ENOMEM;
  218                 }
  219                 if (pcb->pcb_ldt) {
  220                         bcopy(pcb->pcb_ldt, new_ldt, pcb->pcb_ldt_len
  221                                 * sizeof(union descriptor));
  222                         kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt,
  223                                 pcb->pcb_ldt_len * sizeof(union descriptor));
  224                 } else {
  225                         bcopy(ldt, new_ldt, sizeof(ldt));
  226                 }
  227                 pcb->pcb_ldt = (caddr_t)new_ldt;
  228                 pcb->pcb_ldt_len = NEW_MAX_LD(largest_ld);
  229                 if (pcb == curpcb)
  230                     set_user_ldt(pcb);
  231         }
  232 
  233         /* Check descriptors for access violations */
  234         for (i = 0, n = uap->start; i < uap->num; i++, n++) {
  235                 union descriptor desc, *dp;
  236                 dp = &uap->desc[i];
  237                 error = copyin(dp, &desc, sizeof(union descriptor));
  238                 if (error)
  239                         return(error);
  240 
  241                 switch (desc.sd.sd_type) {
  242                 case SDT_SYSNULL:       /* system null */ 
  243                         desc.sd.sd_p = 0;
  244                         break;
  245                 case SDT_SYS286TSS: /* system 286 TSS available */
  246                 case SDT_SYSLDT:    /* system local descriptor table */
  247                 case SDT_SYS286BSY: /* system 286 TSS busy */
  248                 case SDT_SYSTASKGT: /* system task gate */
  249                 case SDT_SYS286IGT: /* system 286 interrupt gate */
  250                 case SDT_SYS286TGT: /* system 286 trap gate */
  251                 case SDT_SYSNULL2:  /* undefined by Intel */ 
  252                 case SDT_SYS386TSS: /* system 386 TSS available */
  253                 case SDT_SYSNULL3:  /* undefined by Intel */
  254                 case SDT_SYS386BSY: /* system 386 TSS busy */
  255                 case SDT_SYSNULL4:  /* undefined by Intel */ 
  256                 case SDT_SYS386IGT: /* system 386 interrupt gate */
  257                 case SDT_SYS386TGT: /* system 386 trap gate */
  258                 case SDT_SYS286CGT: /* system 286 call gate */ 
  259                 case SDT_SYS386CGT: /* system 386 call gate */
  260                         /* I can't think of any reason to allow a user proc
  261                          * to create a segment of these types.  They are
  262                          * for OS use only.
  263                          */
  264                         return EACCES;
  265  
  266                 /* memory segment types */
  267                 case SDT_MEMEC:   /* memory execute only conforming */
  268                 case SDT_MEMEAC:  /* memory execute only accessed conforming */
  269                 case SDT_MEMERC:  /* memory execute read conforming */
  270                 case SDT_MEMERAC: /* memory execute read accessed conforming */
  271                          /* Must be "present" if executable and conforming. */
  272                          if (desc.sd.sd_p == 0)
  273                                  return (EACCES);
  274                         break;
  275                 case SDT_MEMRO:   /* memory read only */
  276                 case SDT_MEMROA:  /* memory read only accessed */
  277                 case SDT_MEMRW:   /* memory read write */
  278                 case SDT_MEMRWA:  /* memory read write accessed */
  279                 case SDT_MEMROD:  /* memory read only expand dwn limit */
  280                 case SDT_MEMRODA: /* memory read only expand dwn lim accessed */
  281                 case SDT_MEMRWD:  /* memory read write expand dwn limit */  
  282                 case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */
  283                 case SDT_MEME:    /* memory execute only */ 
  284                 case SDT_MEMEA:   /* memory execute only accessed */
  285                 case SDT_MEMER:   /* memory execute read */
  286                 case SDT_MEMERA:  /* memory execute read accessed */
  287                         break;
  288                 default:
  289                         return(EINVAL);
  290                         /*NOTREACHED*/
  291                 }
  292  
  293                 /* Only user (ring-3) descriptors may be present. */
  294                 if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL))
  295                         return (EACCES);
  296         }
  297 
  298         s = splhigh();
  299 
  300         /* Fill in range */
  301         error = copyin(uap->desc, 
  302                  &((union descriptor *)(pcb->pcb_ldt))[uap->start],
  303                 uap->num * sizeof(union descriptor));
  304         if (!error)
  305                 *retval = uap->start;
  306 
  307         splx(s);
  308         return(error);
  309 }
  310 #endif  /* USER_LDT */

Cache object: 6190b3351b15a0ebe87320cdba0305b4


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