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 3448a09cf2SJohn Dyson * $Id: sys_machdep.c,v 1.22 1997/07/20 08:37:23 bde 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> 45996c772fSJohn Dyson #include <sys/lock.h> 46efeaf95aSDavid Greenman #include <vm/pmap.h> 47efeaf95aSDavid Greenman #include <vm/vm_map.h> 48efeaf95aSDavid Greenman #include <vm/vm_extern.h> 49efeaf95aSDavid Greenman 50f540b106SGarrett Wollman #include <sys/user.h> 51812a11a2SDavid Greenman 52f540b106SGarrett Wollman #include <machine/cpu.h> 53f540b106SGarrett Wollman #include <machine/sysarch.h> 5448a09cf2SJohn Dyson #include <machine/pcb_ext.h> 55812a11a2SDavid Greenman 56f540b106SGarrett Wollman #include <vm/vm_kern.h> /* for kernel_map */ 57da59a31cSDavid Greenman 580dbf6d73SJordan K. Hubbard #define MAX_LD 8192 590dbf6d73SJordan K. Hubbard #define LD_PER_PAGE 512 600dbf6d73SJordan K. Hubbard #define NEW_MAX_LD(num) ((num + LD_PER_PAGE) & ~(LD_PER_PAGE-1)) 610dbf6d73SJordan K. Hubbard #define SIZE_FROM_LARGEST_LD(num) (NEW_MAX_LD(num) << 3) 620dbf6d73SJordan K. Hubbard 630dbf6d73SJordan K. Hubbard 640dbf6d73SJordan K. Hubbard 65812a11a2SDavid Greenman void set_user_ldt __P((struct pcb *pcb)); 660b5b0f16SGarrett Wollman #ifdef USER_LDT 6787b91157SPoul-Henning Kamp static int i386_get_ldt __P((struct proc *, char *, int *)); 6887b91157SPoul-Henning Kamp static int i386_set_ldt __P((struct proc *, char *, int *)); 690b5b0f16SGarrett Wollman #endif 7048a09cf2SJohn Dyson #ifdef VM86 7148a09cf2SJohn Dyson static int i386_get_ioperm __P((struct proc *, char *, int *)); 7248a09cf2SJohn Dyson static int i386_set_ioperm __P((struct proc *, char *, int *)); 7348a09cf2SJohn Dyson int i386_extend_pcb __P((struct proc *)); 7448a09cf2SJohn Dyson int (*vm86_sysarch) __P((struct proc *, char *, int *)); 7548a09cf2SJohn Dyson #endif 765b81b6b3SRodney W. Grimes 772f1ba63bSBruce Evans #ifndef _SYS_SYSPROTO_H_ 78812a11a2SDavid Greenman struct sysarch_args { 79812a11a2SDavid Greenman int op; 80812a11a2SDavid Greenman char *parms; 8101ae5b20SDavid Greenman }; 822f1ba63bSBruce Evans #endif 8301ae5b20SDavid Greenman 84812a11a2SDavid Greenman int 85812a11a2SDavid Greenman sysarch(p, uap, retval) 8601ae5b20SDavid Greenman struct proc *p; 87812a11a2SDavid Greenman register struct sysarch_args *uap; 885b81b6b3SRodney W. Grimes int *retval; 895b81b6b3SRodney W. Grimes { 90812a11a2SDavid Greenman int error = 0; 915b81b6b3SRodney W. Grimes 92812a11a2SDavid Greenman switch(uap->op) { 93812a11a2SDavid Greenman #ifdef USER_LDT 94812a11a2SDavid Greenman case I386_GET_LDT: 95812a11a2SDavid Greenman error = i386_get_ldt(p, uap->parms, retval); 965b81b6b3SRodney W. Grimes break; 975b81b6b3SRodney W. Grimes 98812a11a2SDavid Greenman case I386_SET_LDT: 99812a11a2SDavid Greenman error = i386_set_ldt(p, uap->parms, retval); 1005b81b6b3SRodney W. Grimes break; 1015b81b6b3SRodney W. Grimes #endif 10248a09cf2SJohn Dyson #ifdef VM86 10348a09cf2SJohn Dyson case I386_GET_IOPERM: 10448a09cf2SJohn Dyson error = i386_get_ioperm(p, uap->parms, retval); 10548a09cf2SJohn Dyson break; 10648a09cf2SJohn Dyson case I386_SET_IOPERM: 10748a09cf2SJohn Dyson error = i386_set_ioperm(p, uap->parms, retval); 10848a09cf2SJohn Dyson break; 10948a09cf2SJohn Dyson case I386_VM86: 11048a09cf2SJohn Dyson if (vm86_sysarch) { 11148a09cf2SJohn Dyson error = (*vm86_sysarch)(p, uap->parms, retval); 11248a09cf2SJohn Dyson break; 11348a09cf2SJohn Dyson } 11448a09cf2SJohn Dyson /* FALL THROUGH */ 11548a09cf2SJohn Dyson #endif 116812a11a2SDavid Greenman default: 117812a11a2SDavid Greenman error = EINVAL; 118812a11a2SDavid Greenman break; 119812a11a2SDavid Greenman } 120812a11a2SDavid Greenman return (error); 121812a11a2SDavid Greenman } 122da59a31cSDavid Greenman 12348a09cf2SJohn Dyson #ifdef VM86 12448a09cf2SJohn Dyson int 12548a09cf2SJohn Dyson i386_extend_pcb(struct proc *p) 12648a09cf2SJohn Dyson { 12748a09cf2SJohn Dyson int i, offset; 12848a09cf2SJohn Dyson u_long *addr; 12948a09cf2SJohn Dyson struct pcb_ext *ext; 13048a09cf2SJohn Dyson struct segment_descriptor sd; 13148a09cf2SJohn Dyson struct soft_segment_descriptor ssd = { 13248a09cf2SJohn Dyson 0, /* segment base address (overwritten) */ 13348a09cf2SJohn Dyson ctob(IOPAGES + 1) - 1, /* length */ 13448a09cf2SJohn Dyson SDT_SYS386TSS, /* segment type */ 13548a09cf2SJohn Dyson 0, /* priority level */ 13648a09cf2SJohn Dyson 1, /* descriptor present */ 13748a09cf2SJohn Dyson 0, 0, 13848a09cf2SJohn Dyson 0, /* default 32 size */ 13948a09cf2SJohn Dyson 0 /* granularity */ 14048a09cf2SJohn Dyson }; 14148a09cf2SJohn Dyson 14248a09cf2SJohn Dyson ext = (struct pcb_ext *)kmem_alloc(kernel_map, ctob(IOPAGES+1)); 14348a09cf2SJohn Dyson if (ext == 0) 14448a09cf2SJohn Dyson return (ENOMEM); 14548a09cf2SJohn Dyson p->p_addr->u_pcb.pcb_ext = ext; 14648a09cf2SJohn Dyson bzero(&ext->ext_tss, sizeof(struct i386tss)); 14748a09cf2SJohn Dyson ext->ext_tss.tss_esp0 = (unsigned)p->p_addr + ctob(UPAGES) - 16; 14848a09cf2SJohn Dyson ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); 14948a09cf2SJohn Dyson /* 15048a09cf2SJohn Dyson * The last byte of the i/o map must be followed by an 0xff byte. 15148a09cf2SJohn Dyson * We arbitrarily allocate 16 bytes here, to keep the starting 15248a09cf2SJohn Dyson * address on a doubleword boundary. 15348a09cf2SJohn Dyson */ 15448a09cf2SJohn Dyson offset = PAGE_SIZE - 16; 15548a09cf2SJohn Dyson ext->ext_tss.tss_ioopt = 15648a09cf2SJohn Dyson (offset - ((unsigned)&ext->ext_tss - (unsigned)ext)) << 16; 15748a09cf2SJohn Dyson ext->ext_iomap = (caddr_t)ext + offset; 15848a09cf2SJohn Dyson ext->ext_vm86.vm86_intmap = (caddr_t)ext + offset - 32; 15948a09cf2SJohn Dyson ext->ext_vm86.vm86_inited = 0; 16048a09cf2SJohn Dyson 16148a09cf2SJohn Dyson addr = (u_long *)ext->ext_vm86.vm86_intmap; 16248a09cf2SJohn Dyson for (i = 0; i < (ctob(IOPAGES) + 32 + 16) / sizeof(u_long); i++) 16348a09cf2SJohn Dyson *addr++ = ~0; 16448a09cf2SJohn Dyson 16548a09cf2SJohn Dyson ssd.ssd_base = (unsigned)&ext->ext_tss; 16648a09cf2SJohn Dyson ssd.ssd_limit -= ((unsigned)&ext->ext_tss - (unsigned)ext); 16748a09cf2SJohn Dyson ssdtosd(&ssd, &ext->ext_tssd); 16848a09cf2SJohn Dyson 16948a09cf2SJohn Dyson /* switch to the new TSS after syscall completes */ 17048a09cf2SJohn Dyson need_resched(); 17148a09cf2SJohn Dyson 17248a09cf2SJohn Dyson return 0; 17348a09cf2SJohn Dyson } 17448a09cf2SJohn Dyson 17548a09cf2SJohn Dyson struct i386_ioperm_args { 17648a09cf2SJohn Dyson u_short start; 17748a09cf2SJohn Dyson u_short length; 17848a09cf2SJohn Dyson u_char enable; 17948a09cf2SJohn Dyson }; 18048a09cf2SJohn Dyson 18148a09cf2SJohn Dyson static int 18248a09cf2SJohn Dyson i386_set_ioperm(p, args, retval) 18348a09cf2SJohn Dyson struct proc *p; 18448a09cf2SJohn Dyson char *args; 18548a09cf2SJohn Dyson int *retval; 18648a09cf2SJohn Dyson { 18748a09cf2SJohn Dyson int i, error = 0; 18848a09cf2SJohn Dyson struct i386_ioperm_args ua; 18948a09cf2SJohn Dyson char *iomap; 19048a09cf2SJohn Dyson 19148a09cf2SJohn Dyson if (error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) 19248a09cf2SJohn Dyson return (error); 19348a09cf2SJohn Dyson 19448a09cf2SJohn Dyson /* Only root can do this */ 19548a09cf2SJohn Dyson if (error = suser(p->p_ucred, &p->p_acflag)) 19648a09cf2SJohn Dyson return (error); 19748a09cf2SJohn Dyson /* 19848a09cf2SJohn Dyson * XXX 19948a09cf2SJohn Dyson * While this is restricted to root, we should probably figure out 20048a09cf2SJohn Dyson * whether any other driver is using this i/o address, as so not to 20148a09cf2SJohn Dyson * cause confusion. This probably requires a global 'usage registry'. 20248a09cf2SJohn Dyson */ 20348a09cf2SJohn Dyson 20448a09cf2SJohn Dyson if (p->p_addr->u_pcb.pcb_ext == 0) 20548a09cf2SJohn Dyson if (error = i386_extend_pcb(p)) 20648a09cf2SJohn Dyson return (error); 20748a09cf2SJohn Dyson iomap = (char *)p->p_addr->u_pcb.pcb_ext->ext_iomap; 20848a09cf2SJohn Dyson 20948a09cf2SJohn Dyson if ((int)(ua.start + ua.length) > 0xffff) 21048a09cf2SJohn Dyson return (EINVAL); 21148a09cf2SJohn Dyson 21248a09cf2SJohn Dyson for (i = ua.start; i < (int)(ua.start + ua.length) + 1; i++) { 21348a09cf2SJohn Dyson if (ua.enable) 21448a09cf2SJohn Dyson iomap[i >> 3] &= ~(1 << (i & 7)); 21548a09cf2SJohn Dyson else 21648a09cf2SJohn Dyson iomap[i >> 3] |= (1 << (i & 7)); 21748a09cf2SJohn Dyson } 21848a09cf2SJohn Dyson return (error); 21948a09cf2SJohn Dyson } 22048a09cf2SJohn Dyson 22148a09cf2SJohn Dyson static int 22248a09cf2SJohn Dyson i386_get_ioperm(p, args, retval) 22348a09cf2SJohn Dyson struct proc *p; 22448a09cf2SJohn Dyson char *args; 22548a09cf2SJohn Dyson int *retval; 22648a09cf2SJohn Dyson { 22748a09cf2SJohn Dyson int i, state, error = 0; 22848a09cf2SJohn Dyson struct i386_ioperm_args ua; 22948a09cf2SJohn Dyson char *iomap; 23048a09cf2SJohn Dyson 23148a09cf2SJohn Dyson if (error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) 23248a09cf2SJohn Dyson return (error); 23348a09cf2SJohn Dyson 23448a09cf2SJohn Dyson if (p->p_addr->u_pcb.pcb_ext == 0) { 23548a09cf2SJohn Dyson ua.length = 0; 23648a09cf2SJohn Dyson goto done; 23748a09cf2SJohn Dyson } 23848a09cf2SJohn Dyson 23948a09cf2SJohn Dyson iomap = (char *)p->p_addr->u_pcb.pcb_ext->ext_iomap; 24048a09cf2SJohn Dyson 24148a09cf2SJohn Dyson state = (iomap[i >> 3] >> (i & 7)) & 1; 24248a09cf2SJohn Dyson ua.enable = !state; 24348a09cf2SJohn Dyson ua.length = 1; 24448a09cf2SJohn Dyson 24548a09cf2SJohn Dyson for (i = ua.start + 1; i < 0x10000; i++) { 24648a09cf2SJohn Dyson if (state != ((iomap[i >> 3] >> (i & 7)) & 1)) 24748a09cf2SJohn Dyson break; 24848a09cf2SJohn Dyson ua.length++; 24948a09cf2SJohn Dyson } 25048a09cf2SJohn Dyson 25148a09cf2SJohn Dyson done: 25248a09cf2SJohn Dyson error = copyout(&ua, args, sizeof(struct i386_ioperm_args)); 25348a09cf2SJohn Dyson return (error); 25448a09cf2SJohn Dyson } 25548a09cf2SJohn Dyson #endif /* VM86 */ 25648a09cf2SJohn Dyson 257da59a31cSDavid Greenman #ifdef USER_LDT 2580dbf6d73SJordan K. Hubbard /* 2590dbf6d73SJordan K. Hubbard * Update the GDT entry pointing to the LDT to point to the LDT of the 2600dbf6d73SJordan K. Hubbard * current process. 2610dbf6d73SJordan K. Hubbard */ 262da59a31cSDavid Greenman void 263da59a31cSDavid Greenman set_user_ldt(struct pcb *pcb) 264da59a31cSDavid Greenman { 265da59a31cSDavid Greenman gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)pcb->pcb_ldt; 266da59a31cSDavid Greenman gdt_segs[GUSERLDT_SEL].ssd_limit = (pcb->pcb_ldt_len * sizeof(union descriptor)) - 1; 2676d520d66SBruce Evans ssdtosd(&gdt_segs[GUSERLDT_SEL], &gdt[GUSERLDT_SEL].sd); 268da59a31cSDavid Greenman lldt(GSEL(GUSERLDT_SEL, SEL_KPL)); 269da59a31cSDavid Greenman currentldt = GSEL(GUSERLDT_SEL, SEL_KPL); 270da59a31cSDavid Greenman } 271da59a31cSDavid Greenman 272da59a31cSDavid Greenman struct i386_get_ldt_args { 273da59a31cSDavid Greenman int start; 274da59a31cSDavid Greenman union descriptor *desc; 275da59a31cSDavid Greenman int num; 276da59a31cSDavid Greenman }; 277da59a31cSDavid Greenman 27887b91157SPoul-Henning Kamp static int 279da59a31cSDavid Greenman i386_get_ldt(p, args, retval) 280da59a31cSDavid Greenman struct proc *p; 281da59a31cSDavid Greenman char *args; 282da59a31cSDavid Greenman int *retval; 283da59a31cSDavid Greenman { 284da59a31cSDavid Greenman int error = 0; 285da59a31cSDavid Greenman struct pcb *pcb = &p->p_addr->u_pcb; 286da59a31cSDavid Greenman int nldt, num; 287da59a31cSDavid Greenman union descriptor *lp; 288da59a31cSDavid Greenman int s; 2890dbf6d73SJordan K. Hubbard struct i386_get_ldt_args ua; 2900dbf6d73SJordan K. Hubbard struct i386_get_ldt_args *uap = &ua; 291da59a31cSDavid Greenman 2920dbf6d73SJordan K. Hubbard if ((error = copyin(args, uap, sizeof(struct i386_get_ldt_args))) < 0) 293da59a31cSDavid Greenman return(error); 294da59a31cSDavid Greenman 295da59a31cSDavid Greenman #ifdef DEBUG 2960dbf6d73SJordan K. Hubbard printf("i386_get_ldt: start=%d num=%d descs=%x\n", uap->start, 2970dbf6d73SJordan K. Hubbard uap->num, uap->desc); 298da59a31cSDavid Greenman #endif 299da59a31cSDavid Greenman 3000dbf6d73SJordan K. Hubbard /* verify range of LDTs exist */ 3010dbf6d73SJordan K. Hubbard if ((uap->start < 0) || (uap->num <= 0)) 302da59a31cSDavid Greenman return(EINVAL); 303da59a31cSDavid Greenman 304da59a31cSDavid Greenman s = splhigh(); 305da59a31cSDavid Greenman 306da59a31cSDavid Greenman if (pcb->pcb_ldt) { 307da59a31cSDavid Greenman nldt = pcb->pcb_ldt_len; 308da59a31cSDavid Greenman num = min(uap->num, nldt); 309da59a31cSDavid Greenman lp = &((union descriptor *)(pcb->pcb_ldt))[uap->start]; 310da59a31cSDavid Greenman } else { 311da59a31cSDavid Greenman nldt = sizeof(ldt)/sizeof(ldt[0]); 312da59a31cSDavid Greenman num = min(uap->num, nldt); 313da59a31cSDavid Greenman lp = &ldt[uap->start]; 314da59a31cSDavid Greenman } 315da59a31cSDavid Greenman if (uap->start > nldt) { 316da59a31cSDavid Greenman splx(s); 317da59a31cSDavid Greenman return(EINVAL); 318da59a31cSDavid Greenman } 319da59a31cSDavid Greenman 320da59a31cSDavid Greenman error = copyout(lp, uap->desc, num * sizeof(union descriptor)); 321da59a31cSDavid Greenman if (!error) 322da59a31cSDavid Greenman *retval = num; 323da59a31cSDavid Greenman 324da59a31cSDavid Greenman splx(s); 325da59a31cSDavid Greenman return(error); 326da59a31cSDavid Greenman } 327da59a31cSDavid Greenman 328da59a31cSDavid Greenman struct i386_set_ldt_args { 329da59a31cSDavid Greenman int start; 330da59a31cSDavid Greenman union descriptor *desc; 331da59a31cSDavid Greenman int num; 332da59a31cSDavid Greenman }; 333da59a31cSDavid Greenman 33487b91157SPoul-Henning Kamp static int 335da59a31cSDavid Greenman i386_set_ldt(p, args, retval) 336da59a31cSDavid Greenman struct proc *p; 337da59a31cSDavid Greenman char *args; 338da59a31cSDavid Greenman int *retval; 339da59a31cSDavid Greenman { 340da59a31cSDavid Greenman int error = 0, i, n; 3410dbf6d73SJordan K. Hubbard int largest_ld; 342da59a31cSDavid Greenman struct pcb *pcb = &p->p_addr->u_pcb; 343da59a31cSDavid Greenman int s; 344da59a31cSDavid Greenman struct i386_set_ldt_args ua, *uap; 345da59a31cSDavid Greenman 346da59a31cSDavid Greenman if ((error = copyin(args, &ua, sizeof(struct i386_set_ldt_args))) < 0) 347da59a31cSDavid Greenman return(error); 348da59a31cSDavid Greenman 349da59a31cSDavid Greenman uap = &ua; 350da59a31cSDavid Greenman 351da59a31cSDavid Greenman #ifdef DEBUG 352da59a31cSDavid Greenman printf("i386_set_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc); 353da59a31cSDavid Greenman #endif 354da59a31cSDavid Greenman 3550dbf6d73SJordan K. Hubbard /* verify range of descriptors to modify */ 3568bb9c4c7SSteven Wallace if ((uap->start < 0) || (uap->start >= MAX_LD) || (uap->num < 0) || 3570dbf6d73SJordan K. Hubbard (uap->num > MAX_LD)) 3580dbf6d73SJordan K. Hubbard { 359da59a31cSDavid Greenman return(EINVAL); 3600dbf6d73SJordan K. Hubbard } 3610dbf6d73SJordan K. Hubbard largest_ld = uap->start + uap->num - 1; 3620dbf6d73SJordan K. Hubbard if (largest_ld >= MAX_LD) 363da59a31cSDavid Greenman return(EINVAL); 364da59a31cSDavid Greenman 365da59a31cSDavid Greenman /* allocate user ldt */ 3660dbf6d73SJordan K. Hubbard if (!pcb->pcb_ldt || (largest_ld >= pcb->pcb_ldt_len)) { 3670dbf6d73SJordan K. Hubbard union descriptor *new_ldt = (union descriptor *)kmem_alloc( 3680dbf6d73SJordan K. Hubbard kernel_map, SIZE_FROM_LARGEST_LD(largest_ld)); 3690dbf6d73SJordan K. Hubbard if (new_ldt == NULL) { 3700dbf6d73SJordan K. Hubbard return ENOMEM; 3710dbf6d73SJordan K. Hubbard } 3720dbf6d73SJordan K. Hubbard if (pcb->pcb_ldt) { 3730dbf6d73SJordan K. Hubbard bcopy(pcb->pcb_ldt, new_ldt, pcb->pcb_ldt_len 3740dbf6d73SJordan K. Hubbard * sizeof(union descriptor)); 3750dbf6d73SJordan K. Hubbard kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt, 3760dbf6d73SJordan K. Hubbard pcb->pcb_ldt_len * sizeof(union descriptor)); 3770dbf6d73SJordan K. Hubbard } else { 378da59a31cSDavid Greenman bcopy(ldt, new_ldt, sizeof(ldt)); 3790dbf6d73SJordan K. Hubbard } 380da59a31cSDavid Greenman pcb->pcb_ldt = (caddr_t)new_ldt; 3810dbf6d73SJordan K. Hubbard pcb->pcb_ldt_len = NEW_MAX_LD(largest_ld); 3820dbf6d73SJordan K. Hubbard if (pcb == curpcb) 3830dbf6d73SJordan K. Hubbard set_user_ldt(pcb); 384da59a31cSDavid Greenman } 385da59a31cSDavid Greenman 386da59a31cSDavid Greenman /* Check descriptors for access violations */ 387da59a31cSDavid Greenman for (i = 0, n = uap->start; i < uap->num; i++, n++) { 388da59a31cSDavid Greenman union descriptor desc, *dp; 389da59a31cSDavid Greenman dp = &uap->desc[i]; 390da59a31cSDavid Greenman error = copyin(dp, &desc, sizeof(union descriptor)); 391da59a31cSDavid Greenman if (error) 392da59a31cSDavid Greenman return(error); 393da59a31cSDavid Greenman 3940dbf6d73SJordan K. Hubbard switch (desc.sd.sd_type) { 3950dbf6d73SJordan K. Hubbard case SDT_SYSNULL: /* system null */ 3960dbf6d73SJordan K. Hubbard desc.sd.sd_p = 0; 3970dbf6d73SJordan K. Hubbard break; 3980dbf6d73SJordan K. Hubbard case SDT_SYS286TSS: /* system 286 TSS available */ 3990dbf6d73SJordan K. Hubbard case SDT_SYSLDT: /* system local descriptor table */ 4000dbf6d73SJordan K. Hubbard case SDT_SYS286BSY: /* system 286 TSS busy */ 4010dbf6d73SJordan K. Hubbard case SDT_SYSTASKGT: /* system task gate */ 4020dbf6d73SJordan K. Hubbard case SDT_SYS286IGT: /* system 286 interrupt gate */ 4030dbf6d73SJordan K. Hubbard case SDT_SYS286TGT: /* system 286 trap gate */ 4040dbf6d73SJordan K. Hubbard case SDT_SYSNULL2: /* undefined by Intel */ 4050dbf6d73SJordan K. Hubbard case SDT_SYS386TSS: /* system 386 TSS available */ 4060dbf6d73SJordan K. Hubbard case SDT_SYSNULL3: /* undefined by Intel */ 4070dbf6d73SJordan K. Hubbard case SDT_SYS386BSY: /* system 386 TSS busy */ 4080dbf6d73SJordan K. Hubbard case SDT_SYSNULL4: /* undefined by Intel */ 4090dbf6d73SJordan K. Hubbard case SDT_SYS386IGT: /* system 386 interrupt gate */ 4100dbf6d73SJordan K. Hubbard case SDT_SYS386TGT: /* system 386 trap gate */ 4110dbf6d73SJordan K. Hubbard case SDT_SYS286CGT: /* system 286 call gate */ 4120dbf6d73SJordan K. Hubbard case SDT_SYS386CGT: /* system 386 call gate */ 4130dbf6d73SJordan K. Hubbard /* I can't think of any reason to allow a user proc 4140dbf6d73SJordan K. Hubbard * to create a segment of these types. They are 4150dbf6d73SJordan K. Hubbard * for OS use only. 4160dbf6d73SJordan K. Hubbard */ 4170dbf6d73SJordan K. Hubbard return EACCES; 418da59a31cSDavid Greenman 4190dbf6d73SJordan K. Hubbard /* memory segment types */ 4200dbf6d73SJordan K. Hubbard case SDT_MEMEC: /* memory execute only conforming */ 4210dbf6d73SJordan K. Hubbard case SDT_MEMEAC: /* memory execute only accessed conforming */ 4220dbf6d73SJordan K. Hubbard case SDT_MEMERC: /* memory execute read conforming */ 4230dbf6d73SJordan K. Hubbard case SDT_MEMERAC: /* memory execute read accessed conforming */ 4240dbf6d73SJordan K. Hubbard /* Must be "present" if executable and conforming. */ 425da59a31cSDavid Greenman if (desc.sd.sd_p == 0) 426da59a31cSDavid Greenman return (EACCES); 427da59a31cSDavid Greenman break; 4280dbf6d73SJordan K. Hubbard case SDT_MEMRO: /* memory read only */ 4290dbf6d73SJordan K. Hubbard case SDT_MEMROA: /* memory read only accessed */ 4300dbf6d73SJordan K. Hubbard case SDT_MEMRW: /* memory read write */ 4310dbf6d73SJordan K. Hubbard case SDT_MEMRWA: /* memory read write accessed */ 4320dbf6d73SJordan K. Hubbard case SDT_MEMROD: /* memory read only expand dwn limit */ 4330dbf6d73SJordan K. Hubbard case SDT_MEMRODA: /* memory read only expand dwn lim accessed */ 4340dbf6d73SJordan K. Hubbard case SDT_MEMRWD: /* memory read write expand dwn limit */ 4350dbf6d73SJordan K. Hubbard case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */ 4360dbf6d73SJordan K. Hubbard case SDT_MEME: /* memory execute only */ 4370dbf6d73SJordan K. Hubbard case SDT_MEMEA: /* memory execute only accessed */ 4380dbf6d73SJordan K. Hubbard case SDT_MEMER: /* memory execute read */ 4390dbf6d73SJordan K. Hubbard case SDT_MEMERA: /* memory execute read accessed */ 440da59a31cSDavid Greenman break; 441da59a31cSDavid Greenman default: 4420dbf6d73SJordan K. Hubbard return(EINVAL); 443da59a31cSDavid Greenman /*NOTREACHED*/ 444da59a31cSDavid Greenman } 4450dbf6d73SJordan K. Hubbard 4460dbf6d73SJordan K. Hubbard /* Only user (ring-3) descriptors may be present. */ 4470dbf6d73SJordan K. Hubbard if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL)) 4480dbf6d73SJordan K. Hubbard return (EACCES); 449da59a31cSDavid Greenman } 450da59a31cSDavid Greenman 451da59a31cSDavid Greenman s = splhigh(); 452da59a31cSDavid Greenman 453da59a31cSDavid Greenman /* Fill in range */ 4540dbf6d73SJordan K. Hubbard error = copyin(uap->desc, 4550dbf6d73SJordan K. Hubbard &((union descriptor *)(pcb->pcb_ldt))[uap->start], 4560dbf6d73SJordan K. Hubbard uap->num * sizeof(union descriptor)); 4570dbf6d73SJordan K. Hubbard if (!error) 458da59a31cSDavid Greenman *retval = uap->start; 459da59a31cSDavid Greenman 460da59a31cSDavid Greenman splx(s); 461da59a31cSDavid Greenman return(error); 462da59a31cSDavid Greenman } 463da59a31cSDavid Greenman #endif /* USER_LDT */ 464