15b81b6b3SRodney W. Grimes /*- 25b81b6b3SRodney W. Grimes * Copyright (c) 1990 The Regents of the University of California. 35b81b6b3SRodney W. Grimes * All rights reserved. 45b81b6b3SRodney W. Grimes * 55b81b6b3SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 65b81b6b3SRodney W. Grimes * modification, are permitted provided that the following conditions 75b81b6b3SRodney W. Grimes * are met: 85b81b6b3SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 95b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 105b81b6b3SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 115b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 125b81b6b3SRodney W. Grimes * documentation and/or other materials provided with the distribution. 135b81b6b3SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 145b81b6b3SRodney W. Grimes * must display the following acknowledgement: 155b81b6b3SRodney W. Grimes * This product includes software developed by the University of 165b81b6b3SRodney W. Grimes * California, Berkeley and its contributors. 175b81b6b3SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 185b81b6b3SRodney W. Grimes * may be used to endorse or promote products derived from this software 195b81b6b3SRodney W. Grimes * without specific prior written permission. 205b81b6b3SRodney W. Grimes * 215b81b6b3SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 225b81b6b3SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 235b81b6b3SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 245b81b6b3SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 255b81b6b3SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 265b81b6b3SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 275b81b6b3SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 285b81b6b3SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 295b81b6b3SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 305b81b6b3SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 315b81b6b3SRodney W. Grimes * SUCH DAMAGE. 325b81b6b3SRodney W. Grimes * 3347cacd38SRodney W. Grimes * from: @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91 348bb9c4c7SSteven Wallace * $Id: sys_machdep.c,v 1.17 1996/08/12 19:57:10 wollman Exp $ 35812a11a2SDavid Greenman * 365b81b6b3SRodney W. Grimes */ 375b81b6b3SRodney W. Grimes 38db6a20e2SGarrett Wollman #include "opt_user_ldt.h" 39f540b106SGarrett Wollman #include <sys/param.h> 40f540b106SGarrett Wollman #include <sys/systm.h> 412f1ba63bSBruce Evans #include <sys/sysproto.h> 42f540b106SGarrett Wollman #include <sys/proc.h> 43efeaf95aSDavid Greenman 44efeaf95aSDavid Greenman #include <vm/vm.h> 45efeaf95aSDavid Greenman #include <vm/vm_param.h> 46efeaf95aSDavid Greenman #include <vm/vm_prot.h> 47efeaf95aSDavid Greenman #include <vm/lock.h> 48efeaf95aSDavid Greenman #include <vm/pmap.h> 49efeaf95aSDavid Greenman #include <vm/vm_map.h> 50efeaf95aSDavid Greenman #include <vm/vm_extern.h> 51efeaf95aSDavid Greenman 52f540b106SGarrett Wollman #include <sys/user.h> 53812a11a2SDavid Greenman 54f540b106SGarrett Wollman #include <machine/cpu.h> 55f540b106SGarrett Wollman #include <machine/sysarch.h> 56812a11a2SDavid Greenman 57f540b106SGarrett Wollman #include <vm/vm_kern.h> /* for kernel_map */ 58da59a31cSDavid Greenman 590dbf6d73SJordan K. Hubbard #define MAX_LD 8192 600dbf6d73SJordan K. Hubbard #define LD_PER_PAGE 512 610dbf6d73SJordan K. Hubbard #define NEW_MAX_LD(num) ((num + LD_PER_PAGE) & ~(LD_PER_PAGE-1)) 620dbf6d73SJordan K. Hubbard #define SIZE_FROM_LARGEST_LD(num) (NEW_MAX_LD(num) << 3) 630dbf6d73SJordan K. Hubbard 640dbf6d73SJordan K. Hubbard 650dbf6d73SJordan K. Hubbard 66812a11a2SDavid Greenman void set_user_ldt __P((struct pcb *pcb)); 670b5b0f16SGarrett Wollman #ifdef USER_LDT 6887b91157SPoul-Henning Kamp static int i386_get_ldt __P((struct proc *, char *, int *)); 6987b91157SPoul-Henning Kamp static int i386_set_ldt __P((struct proc *, char *, int *)); 700b5b0f16SGarrett Wollman #endif 715b81b6b3SRodney W. Grimes 722f1ba63bSBruce Evans #ifndef _SYS_SYSPROTO_H_ 73812a11a2SDavid Greenman struct sysarch_args { 74812a11a2SDavid Greenman int op; 75812a11a2SDavid Greenman char *parms; 7601ae5b20SDavid Greenman }; 772f1ba63bSBruce Evans #endif 7801ae5b20SDavid Greenman 79812a11a2SDavid Greenman int 80812a11a2SDavid Greenman sysarch(p, uap, retval) 8101ae5b20SDavid Greenman struct proc *p; 82812a11a2SDavid Greenman register struct sysarch_args *uap; 835b81b6b3SRodney W. Grimes int *retval; 845b81b6b3SRodney W. Grimes { 85812a11a2SDavid Greenman int error = 0; 865b81b6b3SRodney W. Grimes 87812a11a2SDavid Greenman switch(uap->op) { 88812a11a2SDavid Greenman #ifdef USER_LDT 89812a11a2SDavid Greenman case I386_GET_LDT: 90812a11a2SDavid Greenman error = i386_get_ldt(p, uap->parms, retval); 915b81b6b3SRodney W. Grimes break; 925b81b6b3SRodney W. Grimes 93812a11a2SDavid Greenman case I386_SET_LDT: 94812a11a2SDavid Greenman error = i386_set_ldt(p, uap->parms, retval); 955b81b6b3SRodney W. Grimes break; 965b81b6b3SRodney W. Grimes #endif 97812a11a2SDavid Greenman default: 98812a11a2SDavid Greenman error = EINVAL; 99812a11a2SDavid Greenman break; 100812a11a2SDavid Greenman } 101812a11a2SDavid Greenman return(error); 102812a11a2SDavid Greenman } 103da59a31cSDavid Greenman 104da59a31cSDavid Greenman #ifdef USER_LDT 1050dbf6d73SJordan K. Hubbard /* 1060dbf6d73SJordan K. Hubbard * Update the GDT entry pointing to the LDT to point to the LDT of the 1070dbf6d73SJordan K. Hubbard * current process. 1080dbf6d73SJordan K. Hubbard */ 109da59a31cSDavid Greenman void 110da59a31cSDavid Greenman set_user_ldt(struct pcb *pcb) 111da59a31cSDavid Greenman { 112da59a31cSDavid Greenman gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)pcb->pcb_ldt; 113da59a31cSDavid Greenman gdt_segs[GUSERLDT_SEL].ssd_limit = (pcb->pcb_ldt_len * sizeof(union descriptor)) - 1; 1146d520d66SBruce Evans ssdtosd(&gdt_segs[GUSERLDT_SEL], &gdt[GUSERLDT_SEL].sd); 115da59a31cSDavid Greenman lldt(GSEL(GUSERLDT_SEL, SEL_KPL)); 116da59a31cSDavid Greenman currentldt = GSEL(GUSERLDT_SEL, SEL_KPL); 117da59a31cSDavid Greenman } 118da59a31cSDavid Greenman 119da59a31cSDavid Greenman struct i386_get_ldt_args { 120da59a31cSDavid Greenman int start; 121da59a31cSDavid Greenman union descriptor *desc; 122da59a31cSDavid Greenman int num; 123da59a31cSDavid Greenman }; 124da59a31cSDavid Greenman 12587b91157SPoul-Henning Kamp static int 126da59a31cSDavid Greenman i386_get_ldt(p, args, retval) 127da59a31cSDavid Greenman struct proc *p; 128da59a31cSDavid Greenman char *args; 129da59a31cSDavid Greenman int *retval; 130da59a31cSDavid Greenman { 131da59a31cSDavid Greenman int error = 0; 132da59a31cSDavid Greenman struct pcb *pcb = &p->p_addr->u_pcb; 133da59a31cSDavid Greenman int nldt, num; 134da59a31cSDavid Greenman union descriptor *lp; 135da59a31cSDavid Greenman int s; 1360dbf6d73SJordan K. Hubbard struct i386_get_ldt_args ua; 1370dbf6d73SJordan K. Hubbard struct i386_get_ldt_args *uap = &ua; 138da59a31cSDavid Greenman 1390dbf6d73SJordan K. Hubbard if ((error = copyin(args, uap, sizeof(struct i386_get_ldt_args))) < 0) 140da59a31cSDavid Greenman return(error); 141da59a31cSDavid Greenman 142da59a31cSDavid Greenman #ifdef DEBUG 1430dbf6d73SJordan K. Hubbard printf("i386_get_ldt: start=%d num=%d descs=%x\n", uap->start, 1440dbf6d73SJordan K. Hubbard uap->num, uap->desc); 145da59a31cSDavid Greenman #endif 146da59a31cSDavid Greenman 1470dbf6d73SJordan K. Hubbard /* verify range of LDTs exist */ 1480dbf6d73SJordan K. Hubbard if ((uap->start < 0) || (uap->num <= 0)) 149da59a31cSDavid Greenman return(EINVAL); 150da59a31cSDavid Greenman 151da59a31cSDavid Greenman s = splhigh(); 152da59a31cSDavid Greenman 153da59a31cSDavid Greenman if (pcb->pcb_ldt) { 154da59a31cSDavid Greenman nldt = pcb->pcb_ldt_len; 155da59a31cSDavid Greenman num = min(uap->num, nldt); 156da59a31cSDavid Greenman lp = &((union descriptor *)(pcb->pcb_ldt))[uap->start]; 157da59a31cSDavid Greenman } else { 158da59a31cSDavid Greenman nldt = sizeof(ldt)/sizeof(ldt[0]); 159da59a31cSDavid Greenman num = min(uap->num, nldt); 160da59a31cSDavid Greenman lp = &ldt[uap->start]; 161da59a31cSDavid Greenman } 162da59a31cSDavid Greenman if (uap->start > nldt) { 163da59a31cSDavid Greenman splx(s); 164da59a31cSDavid Greenman return(EINVAL); 165da59a31cSDavid Greenman } 166da59a31cSDavid Greenman 167da59a31cSDavid Greenman error = copyout(lp, uap->desc, num * sizeof(union descriptor)); 168da59a31cSDavid Greenman if (!error) 169da59a31cSDavid Greenman *retval = num; 170da59a31cSDavid Greenman 171da59a31cSDavid Greenman splx(s); 172da59a31cSDavid Greenman return(error); 173da59a31cSDavid Greenman } 174da59a31cSDavid Greenman 175da59a31cSDavid Greenman struct i386_set_ldt_args { 176da59a31cSDavid Greenman int start; 177da59a31cSDavid Greenman union descriptor *desc; 178da59a31cSDavid Greenman int num; 179da59a31cSDavid Greenman }; 180da59a31cSDavid Greenman 18187b91157SPoul-Henning Kamp static int 182da59a31cSDavid Greenman i386_set_ldt(p, args, retval) 183da59a31cSDavid Greenman struct proc *p; 184da59a31cSDavid Greenman char *args; 185da59a31cSDavid Greenman int *retval; 186da59a31cSDavid Greenman { 187da59a31cSDavid Greenman int error = 0, i, n; 1880dbf6d73SJordan K. Hubbard int largest_ld; 189da59a31cSDavid Greenman struct pcb *pcb = &p->p_addr->u_pcb; 190da59a31cSDavid Greenman int s; 191da59a31cSDavid Greenman struct i386_set_ldt_args ua, *uap; 192da59a31cSDavid Greenman 193da59a31cSDavid Greenman if ((error = copyin(args, &ua, sizeof(struct i386_set_ldt_args))) < 0) 194da59a31cSDavid Greenman return(error); 195da59a31cSDavid Greenman 196da59a31cSDavid Greenman uap = &ua; 197da59a31cSDavid Greenman 198da59a31cSDavid Greenman #ifdef DEBUG 199da59a31cSDavid Greenman printf("i386_set_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc); 200da59a31cSDavid Greenman #endif 201da59a31cSDavid Greenman 2020dbf6d73SJordan K. Hubbard /* verify range of descriptors to modify */ 2038bb9c4c7SSteven Wallace if ((uap->start < 0) || (uap->start >= MAX_LD) || (uap->num < 0) || 2040dbf6d73SJordan K. Hubbard (uap->num > MAX_LD)) 2050dbf6d73SJordan K. Hubbard { 206da59a31cSDavid Greenman return(EINVAL); 2070dbf6d73SJordan K. Hubbard } 2080dbf6d73SJordan K. Hubbard largest_ld = uap->start + uap->num - 1; 2090dbf6d73SJordan K. Hubbard if (largest_ld >= MAX_LD) 210da59a31cSDavid Greenman return(EINVAL); 211da59a31cSDavid Greenman 212da59a31cSDavid Greenman /* allocate user ldt */ 2130dbf6d73SJordan K. Hubbard if (!pcb->pcb_ldt || (largest_ld >= pcb->pcb_ldt_len)) { 2140dbf6d73SJordan K. Hubbard union descriptor *new_ldt = (union descriptor *)kmem_alloc( 2150dbf6d73SJordan K. Hubbard kernel_map, SIZE_FROM_LARGEST_LD(largest_ld)); 2160dbf6d73SJordan K. Hubbard if (new_ldt == NULL) { 2170dbf6d73SJordan K. Hubbard return ENOMEM; 2180dbf6d73SJordan K. Hubbard } 2190dbf6d73SJordan K. Hubbard if (pcb->pcb_ldt) { 2200dbf6d73SJordan K. Hubbard bcopy(pcb->pcb_ldt, new_ldt, pcb->pcb_ldt_len 2210dbf6d73SJordan K. Hubbard * sizeof(union descriptor)); 2220dbf6d73SJordan K. Hubbard kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt, 2230dbf6d73SJordan K. Hubbard pcb->pcb_ldt_len * sizeof(union descriptor)); 2240dbf6d73SJordan K. Hubbard } else { 225da59a31cSDavid Greenman bcopy(ldt, new_ldt, sizeof(ldt)); 2260dbf6d73SJordan K. Hubbard } 227da59a31cSDavid Greenman pcb->pcb_ldt = (caddr_t)new_ldt; 2280dbf6d73SJordan K. Hubbard pcb->pcb_ldt_len = NEW_MAX_LD(largest_ld); 2290dbf6d73SJordan K. Hubbard if (pcb == curpcb) 2300dbf6d73SJordan K. Hubbard set_user_ldt(pcb); 231da59a31cSDavid Greenman } 232da59a31cSDavid Greenman 233da59a31cSDavid Greenman /* Check descriptors for access violations */ 234da59a31cSDavid Greenman for (i = 0, n = uap->start; i < uap->num; i++, n++) { 235da59a31cSDavid Greenman union descriptor desc, *dp; 236da59a31cSDavid Greenman dp = &uap->desc[i]; 237da59a31cSDavid Greenman error = copyin(dp, &desc, sizeof(union descriptor)); 238da59a31cSDavid Greenman if (error) 239da59a31cSDavid Greenman return(error); 240da59a31cSDavid Greenman 2410dbf6d73SJordan K. Hubbard switch (desc.sd.sd_type) { 2420dbf6d73SJordan K. Hubbard case SDT_SYSNULL: /* system null */ 2430dbf6d73SJordan K. Hubbard desc.sd.sd_p = 0; 2440dbf6d73SJordan K. Hubbard break; 2450dbf6d73SJordan K. Hubbard case SDT_SYS286TSS: /* system 286 TSS available */ 2460dbf6d73SJordan K. Hubbard case SDT_SYSLDT: /* system local descriptor table */ 2470dbf6d73SJordan K. Hubbard case SDT_SYS286BSY: /* system 286 TSS busy */ 2480dbf6d73SJordan K. Hubbard case SDT_SYSTASKGT: /* system task gate */ 2490dbf6d73SJordan K. Hubbard case SDT_SYS286IGT: /* system 286 interrupt gate */ 2500dbf6d73SJordan K. Hubbard case SDT_SYS286TGT: /* system 286 trap gate */ 2510dbf6d73SJordan K. Hubbard case SDT_SYSNULL2: /* undefined by Intel */ 2520dbf6d73SJordan K. Hubbard case SDT_SYS386TSS: /* system 386 TSS available */ 2530dbf6d73SJordan K. Hubbard case SDT_SYSNULL3: /* undefined by Intel */ 2540dbf6d73SJordan K. Hubbard case SDT_SYS386BSY: /* system 386 TSS busy */ 2550dbf6d73SJordan K. Hubbard case SDT_SYSNULL4: /* undefined by Intel */ 2560dbf6d73SJordan K. Hubbard case SDT_SYS386IGT: /* system 386 interrupt gate */ 2570dbf6d73SJordan K. Hubbard case SDT_SYS386TGT: /* system 386 trap gate */ 2580dbf6d73SJordan K. Hubbard case SDT_SYS286CGT: /* system 286 call gate */ 2590dbf6d73SJordan K. Hubbard case SDT_SYS386CGT: /* system 386 call gate */ 2600dbf6d73SJordan K. Hubbard /* I can't think of any reason to allow a user proc 2610dbf6d73SJordan K. Hubbard * to create a segment of these types. They are 2620dbf6d73SJordan K. Hubbard * for OS use only. 2630dbf6d73SJordan K. Hubbard */ 2640dbf6d73SJordan K. Hubbard return EACCES; 265da59a31cSDavid Greenman 2660dbf6d73SJordan K. Hubbard /* memory segment types */ 2670dbf6d73SJordan K. Hubbard case SDT_MEMEC: /* memory execute only conforming */ 2680dbf6d73SJordan K. Hubbard case SDT_MEMEAC: /* memory execute only accessed conforming */ 2690dbf6d73SJordan K. Hubbard case SDT_MEMERC: /* memory execute read conforming */ 2700dbf6d73SJordan K. Hubbard case SDT_MEMERAC: /* memory execute read accessed conforming */ 2710dbf6d73SJordan K. Hubbard /* Must be "present" if executable and conforming. */ 272da59a31cSDavid Greenman if (desc.sd.sd_p == 0) 273da59a31cSDavid Greenman return (EACCES); 274da59a31cSDavid Greenman break; 2750dbf6d73SJordan K. Hubbard case SDT_MEMRO: /* memory read only */ 2760dbf6d73SJordan K. Hubbard case SDT_MEMROA: /* memory read only accessed */ 2770dbf6d73SJordan K. Hubbard case SDT_MEMRW: /* memory read write */ 2780dbf6d73SJordan K. Hubbard case SDT_MEMRWA: /* memory read write accessed */ 2790dbf6d73SJordan K. Hubbard case SDT_MEMROD: /* memory read only expand dwn limit */ 2800dbf6d73SJordan K. Hubbard case SDT_MEMRODA: /* memory read only expand dwn lim accessed */ 2810dbf6d73SJordan K. Hubbard case SDT_MEMRWD: /* memory read write expand dwn limit */ 2820dbf6d73SJordan K. Hubbard case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */ 2830dbf6d73SJordan K. Hubbard case SDT_MEME: /* memory execute only */ 2840dbf6d73SJordan K. Hubbard case SDT_MEMEA: /* memory execute only accessed */ 2850dbf6d73SJordan K. Hubbard case SDT_MEMER: /* memory execute read */ 2860dbf6d73SJordan K. Hubbard case SDT_MEMERA: /* memory execute read accessed */ 287da59a31cSDavid Greenman break; 288da59a31cSDavid Greenman default: 2890dbf6d73SJordan K. Hubbard return(EINVAL); 290da59a31cSDavid Greenman /*NOTREACHED*/ 291da59a31cSDavid Greenman } 2920dbf6d73SJordan K. Hubbard 2930dbf6d73SJordan K. Hubbard /* Only user (ring-3) descriptors may be present. */ 2940dbf6d73SJordan K. Hubbard if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL)) 2950dbf6d73SJordan K. Hubbard return (EACCES); 296da59a31cSDavid Greenman } 297da59a31cSDavid Greenman 298da59a31cSDavid Greenman s = splhigh(); 299da59a31cSDavid Greenman 300da59a31cSDavid Greenman /* Fill in range */ 3010dbf6d73SJordan K. Hubbard error = copyin(uap->desc, 3020dbf6d73SJordan K. Hubbard &((union descriptor *)(pcb->pcb_ldt))[uap->start], 3030dbf6d73SJordan K. Hubbard uap->num * sizeof(union descriptor)); 3040dbf6d73SJordan K. Hubbard if (!error) 305da59a31cSDavid Greenman *retval = uap->start; 306da59a31cSDavid Greenman 307da59a31cSDavid Greenman splx(s); 308da59a31cSDavid Greenman return(error); 309da59a31cSDavid Greenman } 310da59a31cSDavid Greenman #endif /* USER_LDT */ 311