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 34b67dffdaSPeter Wemm * $Id: sys_machdep.c,v 1.26 1997/10/10 09:44:08 peter Exp $ 35812a11a2SDavid Greenman * 365b81b6b3SRodney W. Grimes */ 375b81b6b3SRodney W. Grimes 38db6a20e2SGarrett Wollman #include "opt_user_ldt.h" 3998823b23SPeter Wemm #include "opt_vm86.h" 4098823b23SPeter Wemm 41f540b106SGarrett Wollman #include <sys/param.h> 42f540b106SGarrett Wollman #include <sys/systm.h> 432f1ba63bSBruce Evans #include <sys/sysproto.h> 44f540b106SGarrett Wollman #include <sys/proc.h> 45efeaf95aSDavid Greenman 46efeaf95aSDavid Greenman #include <vm/vm.h> 47996c772fSJohn Dyson #include <sys/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> 55b67dffdaSPeter Wemm #include <machine/pcb_ext.h> /* pcb.h included by sys/user.h */ 56f540b106SGarrett Wollman #include <machine/sysarch.h> 57812a11a2SDavid Greenman 58f540b106SGarrett Wollman #include <vm/vm_kern.h> /* for kernel_map */ 59da59a31cSDavid Greenman 600dbf6d73SJordan K. Hubbard #define MAX_LD 8192 610dbf6d73SJordan K. Hubbard #define LD_PER_PAGE 512 620dbf6d73SJordan K. Hubbard #define NEW_MAX_LD(num) ((num + LD_PER_PAGE) & ~(LD_PER_PAGE-1)) 630dbf6d73SJordan K. Hubbard #define SIZE_FROM_LARGEST_LD(num) (NEW_MAX_LD(num) << 3) 640dbf6d73SJordan K. Hubbard 650dbf6d73SJordan K. Hubbard 660dbf6d73SJordan K. Hubbard 67812a11a2SDavid Greenman void set_user_ldt __P((struct pcb *pcb)); 680b5b0f16SGarrett Wollman #ifdef USER_LDT 6987b91157SPoul-Henning Kamp static int i386_get_ldt __P((struct proc *, char *, int *)); 7087b91157SPoul-Henning Kamp static int i386_set_ldt __P((struct proc *, char *, int *)); 710b5b0f16SGarrett Wollman #endif 7248a09cf2SJohn Dyson #ifdef VM86 7348a09cf2SJohn Dyson static int i386_get_ioperm __P((struct proc *, char *, int *)); 7448a09cf2SJohn Dyson static int i386_set_ioperm __P((struct proc *, char *, int *)); 7548a09cf2SJohn Dyson int i386_extend_pcb __P((struct proc *)); 7648a09cf2SJohn Dyson #endif 775b81b6b3SRodney W. Grimes 782f1ba63bSBruce Evans #ifndef _SYS_SYSPROTO_H_ 79812a11a2SDavid Greenman struct sysarch_args { 80812a11a2SDavid Greenman int op; 81812a11a2SDavid Greenman char *parms; 8201ae5b20SDavid Greenman }; 832f1ba63bSBruce Evans #endif 8401ae5b20SDavid Greenman 85812a11a2SDavid Greenman int 86812a11a2SDavid Greenman sysarch(p, uap, retval) 8701ae5b20SDavid Greenman struct proc *p; 88812a11a2SDavid Greenman register struct sysarch_args *uap; 895b81b6b3SRodney W. Grimes int *retval; 905b81b6b3SRodney W. Grimes { 91812a11a2SDavid Greenman int error = 0; 925b81b6b3SRodney W. Grimes 93812a11a2SDavid Greenman switch(uap->op) { 94812a11a2SDavid Greenman #ifdef USER_LDT 95812a11a2SDavid Greenman case I386_GET_LDT: 96812a11a2SDavid Greenman error = i386_get_ldt(p, uap->parms, retval); 975b81b6b3SRodney W. Grimes break; 985b81b6b3SRodney W. Grimes 99812a11a2SDavid Greenman case I386_SET_LDT: 100812a11a2SDavid Greenman error = i386_set_ldt(p, uap->parms, retval); 1015b81b6b3SRodney W. Grimes break; 1025b81b6b3SRodney W. Grimes #endif 10348a09cf2SJohn Dyson #ifdef VM86 10448a09cf2SJohn Dyson case I386_GET_IOPERM: 10548a09cf2SJohn Dyson error = i386_get_ioperm(p, uap->parms, retval); 10648a09cf2SJohn Dyson break; 10748a09cf2SJohn Dyson case I386_SET_IOPERM: 10848a09cf2SJohn Dyson error = i386_set_ioperm(p, uap->parms, retval); 10948a09cf2SJohn Dyson break; 11048a09cf2SJohn Dyson case I386_VM86: 1115f073933SJonathan Lemon error = vm86_sysarch(p, uap->parms, retval); 11248a09cf2SJohn Dyson break; 11348a09cf2SJohn Dyson #endif 114812a11a2SDavid Greenman default: 115812a11a2SDavid Greenman error = EINVAL; 116812a11a2SDavid Greenman break; 117812a11a2SDavid Greenman } 118812a11a2SDavid Greenman return (error); 119812a11a2SDavid Greenman } 120da59a31cSDavid Greenman 12148a09cf2SJohn Dyson #ifdef VM86 12248a09cf2SJohn Dyson int 12348a09cf2SJohn Dyson i386_extend_pcb(struct proc *p) 12448a09cf2SJohn Dyson { 12548a09cf2SJohn Dyson int i, offset; 12648a09cf2SJohn Dyson u_long *addr; 12748a09cf2SJohn Dyson struct pcb_ext *ext; 12848a09cf2SJohn Dyson struct segment_descriptor sd; 12948a09cf2SJohn Dyson struct soft_segment_descriptor ssd = { 13048a09cf2SJohn Dyson 0, /* segment base address (overwritten) */ 13148a09cf2SJohn Dyson ctob(IOPAGES + 1) - 1, /* length */ 13248a09cf2SJohn Dyson SDT_SYS386TSS, /* segment type */ 13348a09cf2SJohn Dyson 0, /* priority level */ 13448a09cf2SJohn Dyson 1, /* descriptor present */ 13548a09cf2SJohn Dyson 0, 0, 13648a09cf2SJohn Dyson 0, /* default 32 size */ 13748a09cf2SJohn Dyson 0 /* granularity */ 13848a09cf2SJohn Dyson }; 13948a09cf2SJohn Dyson 14048a09cf2SJohn Dyson ext = (struct pcb_ext *)kmem_alloc(kernel_map, ctob(IOPAGES+1)); 14148a09cf2SJohn Dyson if (ext == 0) 14248a09cf2SJohn Dyson return (ENOMEM); 14348a09cf2SJohn Dyson p->p_addr->u_pcb.pcb_ext = ext; 14448a09cf2SJohn Dyson bzero(&ext->ext_tss, sizeof(struct i386tss)); 14548a09cf2SJohn Dyson ext->ext_tss.tss_esp0 = (unsigned)p->p_addr + ctob(UPAGES) - 16; 14648a09cf2SJohn Dyson ext->ext_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); 14748a09cf2SJohn Dyson /* 14848a09cf2SJohn Dyson * The last byte of the i/o map must be followed by an 0xff byte. 14948a09cf2SJohn Dyson * We arbitrarily allocate 16 bytes here, to keep the starting 15048a09cf2SJohn Dyson * address on a doubleword boundary. 15148a09cf2SJohn Dyson */ 15248a09cf2SJohn Dyson offset = PAGE_SIZE - 16; 15348a09cf2SJohn Dyson ext->ext_tss.tss_ioopt = 15448a09cf2SJohn Dyson (offset - ((unsigned)&ext->ext_tss - (unsigned)ext)) << 16; 15548a09cf2SJohn Dyson ext->ext_iomap = (caddr_t)ext + offset; 15648a09cf2SJohn Dyson ext->ext_vm86.vm86_intmap = (caddr_t)ext + offset - 32; 15748a09cf2SJohn Dyson ext->ext_vm86.vm86_inited = 0; 15848a09cf2SJohn Dyson 15948a09cf2SJohn Dyson addr = (u_long *)ext->ext_vm86.vm86_intmap; 16048a09cf2SJohn Dyson for (i = 0; i < (ctob(IOPAGES) + 32 + 16) / sizeof(u_long); i++) 16148a09cf2SJohn Dyson *addr++ = ~0; 16248a09cf2SJohn Dyson 16348a09cf2SJohn Dyson ssd.ssd_base = (unsigned)&ext->ext_tss; 16448a09cf2SJohn Dyson ssd.ssd_limit -= ((unsigned)&ext->ext_tss - (unsigned)ext); 16548a09cf2SJohn Dyson ssdtosd(&ssd, &ext->ext_tssd); 16648a09cf2SJohn Dyson 16748a09cf2SJohn Dyson /* switch to the new TSS after syscall completes */ 16848a09cf2SJohn Dyson need_resched(); 16948a09cf2SJohn Dyson 17048a09cf2SJohn Dyson return 0; 17148a09cf2SJohn Dyson } 17248a09cf2SJohn Dyson 17348a09cf2SJohn Dyson struct i386_ioperm_args { 17448a09cf2SJohn Dyson u_short start; 17548a09cf2SJohn Dyson u_short length; 17648a09cf2SJohn Dyson u_char enable; 17748a09cf2SJohn Dyson }; 17848a09cf2SJohn Dyson 17948a09cf2SJohn Dyson static int 18048a09cf2SJohn Dyson i386_set_ioperm(p, args, retval) 18148a09cf2SJohn Dyson struct proc *p; 18248a09cf2SJohn Dyson char *args; 18348a09cf2SJohn Dyson int *retval; 18448a09cf2SJohn Dyson { 18548a09cf2SJohn Dyson int i, error = 0; 18648a09cf2SJohn Dyson struct i386_ioperm_args ua; 18748a09cf2SJohn Dyson char *iomap; 18848a09cf2SJohn Dyson 18948a09cf2SJohn Dyson if (error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) 19048a09cf2SJohn Dyson return (error); 19148a09cf2SJohn Dyson 19248a09cf2SJohn Dyson /* Only root can do this */ 19348a09cf2SJohn Dyson if (error = suser(p->p_ucred, &p->p_acflag)) 19448a09cf2SJohn Dyson return (error); 19548a09cf2SJohn Dyson /* 19648a09cf2SJohn Dyson * XXX 19748a09cf2SJohn Dyson * While this is restricted to root, we should probably figure out 19848a09cf2SJohn Dyson * whether any other driver is using this i/o address, as so not to 19948a09cf2SJohn Dyson * cause confusion. This probably requires a global 'usage registry'. 20048a09cf2SJohn Dyson */ 20148a09cf2SJohn Dyson 20248a09cf2SJohn Dyson if (p->p_addr->u_pcb.pcb_ext == 0) 20348a09cf2SJohn Dyson if (error = i386_extend_pcb(p)) 20448a09cf2SJohn Dyson return (error); 20548a09cf2SJohn Dyson iomap = (char *)p->p_addr->u_pcb.pcb_ext->ext_iomap; 20648a09cf2SJohn Dyson 20748a09cf2SJohn Dyson if ((int)(ua.start + ua.length) > 0xffff) 20848a09cf2SJohn Dyson return (EINVAL); 20948a09cf2SJohn Dyson 21048a09cf2SJohn Dyson for (i = ua.start; i < (int)(ua.start + ua.length) + 1; i++) { 21148a09cf2SJohn Dyson if (ua.enable) 21248a09cf2SJohn Dyson iomap[i >> 3] &= ~(1 << (i & 7)); 21348a09cf2SJohn Dyson else 21448a09cf2SJohn Dyson iomap[i >> 3] |= (1 << (i & 7)); 21548a09cf2SJohn Dyson } 21648a09cf2SJohn Dyson return (error); 21748a09cf2SJohn Dyson } 21848a09cf2SJohn Dyson 21948a09cf2SJohn Dyson static int 22048a09cf2SJohn Dyson i386_get_ioperm(p, args, retval) 22148a09cf2SJohn Dyson struct proc *p; 22248a09cf2SJohn Dyson char *args; 22348a09cf2SJohn Dyson int *retval; 22448a09cf2SJohn Dyson { 22548a09cf2SJohn Dyson int i, state, error = 0; 22648a09cf2SJohn Dyson struct i386_ioperm_args ua; 22748a09cf2SJohn Dyson char *iomap; 22848a09cf2SJohn Dyson 22948a09cf2SJohn Dyson if (error = copyin(args, &ua, sizeof(struct i386_ioperm_args))) 23048a09cf2SJohn Dyson return (error); 23148a09cf2SJohn Dyson 23248a09cf2SJohn Dyson if (p->p_addr->u_pcb.pcb_ext == 0) { 23348a09cf2SJohn Dyson ua.length = 0; 23448a09cf2SJohn Dyson goto done; 23548a09cf2SJohn Dyson } 23648a09cf2SJohn Dyson 23748a09cf2SJohn Dyson iomap = (char *)p->p_addr->u_pcb.pcb_ext->ext_iomap; 23848a09cf2SJohn Dyson 23948a09cf2SJohn Dyson state = (iomap[i >> 3] >> (i & 7)) & 1; 24048a09cf2SJohn Dyson ua.enable = !state; 24148a09cf2SJohn Dyson ua.length = 1; 24248a09cf2SJohn Dyson 24348a09cf2SJohn Dyson for (i = ua.start + 1; i < 0x10000; i++) { 24448a09cf2SJohn Dyson if (state != ((iomap[i >> 3] >> (i & 7)) & 1)) 24548a09cf2SJohn Dyson break; 24648a09cf2SJohn Dyson ua.length++; 24748a09cf2SJohn Dyson } 24848a09cf2SJohn Dyson 24948a09cf2SJohn Dyson done: 25048a09cf2SJohn Dyson error = copyout(&ua, args, sizeof(struct i386_ioperm_args)); 25148a09cf2SJohn Dyson return (error); 25248a09cf2SJohn Dyson } 25348a09cf2SJohn Dyson #endif /* VM86 */ 25448a09cf2SJohn Dyson 255da59a31cSDavid Greenman #ifdef USER_LDT 2560dbf6d73SJordan K. Hubbard /* 2570dbf6d73SJordan K. Hubbard * Update the GDT entry pointing to the LDT to point to the LDT of the 2580dbf6d73SJordan K. Hubbard * current process. 2590dbf6d73SJordan K. Hubbard */ 260da59a31cSDavid Greenman void 261da59a31cSDavid Greenman set_user_ldt(struct pcb *pcb) 262da59a31cSDavid Greenman { 263da59a31cSDavid Greenman gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)pcb->pcb_ldt; 264da59a31cSDavid Greenman gdt_segs[GUSERLDT_SEL].ssd_limit = (pcb->pcb_ldt_len * sizeof(union descriptor)) - 1; 2656d520d66SBruce Evans ssdtosd(&gdt_segs[GUSERLDT_SEL], &gdt[GUSERLDT_SEL].sd); 266da59a31cSDavid Greenman lldt(GSEL(GUSERLDT_SEL, SEL_KPL)); 267da59a31cSDavid Greenman currentldt = GSEL(GUSERLDT_SEL, SEL_KPL); 268da59a31cSDavid Greenman } 269da59a31cSDavid Greenman 270da59a31cSDavid Greenman struct i386_get_ldt_args { 271da59a31cSDavid Greenman int start; 272da59a31cSDavid Greenman union descriptor *desc; 273da59a31cSDavid Greenman int num; 274da59a31cSDavid Greenman }; 275da59a31cSDavid Greenman 27687b91157SPoul-Henning Kamp static int 277da59a31cSDavid Greenman i386_get_ldt(p, args, retval) 278da59a31cSDavid Greenman struct proc *p; 279da59a31cSDavid Greenman char *args; 280da59a31cSDavid Greenman int *retval; 281da59a31cSDavid Greenman { 282da59a31cSDavid Greenman int error = 0; 283da59a31cSDavid Greenman struct pcb *pcb = &p->p_addr->u_pcb; 284da59a31cSDavid Greenman int nldt, num; 285da59a31cSDavid Greenman union descriptor *lp; 286da59a31cSDavid Greenman int s; 2870dbf6d73SJordan K. Hubbard struct i386_get_ldt_args ua; 2880dbf6d73SJordan K. Hubbard struct i386_get_ldt_args *uap = &ua; 289da59a31cSDavid Greenman 2900dbf6d73SJordan K. Hubbard if ((error = copyin(args, uap, sizeof(struct i386_get_ldt_args))) < 0) 291da59a31cSDavid Greenman return(error); 292da59a31cSDavid Greenman 293da59a31cSDavid Greenman #ifdef DEBUG 2940dbf6d73SJordan K. Hubbard printf("i386_get_ldt: start=%d num=%d descs=%x\n", uap->start, 2950dbf6d73SJordan K. Hubbard uap->num, uap->desc); 296da59a31cSDavid Greenman #endif 297da59a31cSDavid Greenman 2980dbf6d73SJordan K. Hubbard /* verify range of LDTs exist */ 2990dbf6d73SJordan K. Hubbard if ((uap->start < 0) || (uap->num <= 0)) 300da59a31cSDavid Greenman return(EINVAL); 301da59a31cSDavid Greenman 302da59a31cSDavid Greenman s = splhigh(); 303da59a31cSDavid Greenman 304da59a31cSDavid Greenman if (pcb->pcb_ldt) { 305da59a31cSDavid Greenman nldt = pcb->pcb_ldt_len; 306da59a31cSDavid Greenman num = min(uap->num, nldt); 307da59a31cSDavid Greenman lp = &((union descriptor *)(pcb->pcb_ldt))[uap->start]; 308da59a31cSDavid Greenman } else { 309da59a31cSDavid Greenman nldt = sizeof(ldt)/sizeof(ldt[0]); 310da59a31cSDavid Greenman num = min(uap->num, nldt); 311da59a31cSDavid Greenman lp = &ldt[uap->start]; 312da59a31cSDavid Greenman } 313da59a31cSDavid Greenman if (uap->start > nldt) { 314da59a31cSDavid Greenman splx(s); 315da59a31cSDavid Greenman return(EINVAL); 316da59a31cSDavid Greenman } 317da59a31cSDavid Greenman 318da59a31cSDavid Greenman error = copyout(lp, uap->desc, num * sizeof(union descriptor)); 319da59a31cSDavid Greenman if (!error) 320da59a31cSDavid Greenman *retval = num; 321da59a31cSDavid Greenman 322da59a31cSDavid Greenman splx(s); 323da59a31cSDavid Greenman return(error); 324da59a31cSDavid Greenman } 325da59a31cSDavid Greenman 326da59a31cSDavid Greenman struct i386_set_ldt_args { 327da59a31cSDavid Greenman int start; 328da59a31cSDavid Greenman union descriptor *desc; 329da59a31cSDavid Greenman int num; 330da59a31cSDavid Greenman }; 331da59a31cSDavid Greenman 33287b91157SPoul-Henning Kamp static int 333da59a31cSDavid Greenman i386_set_ldt(p, args, retval) 334da59a31cSDavid Greenman struct proc *p; 335da59a31cSDavid Greenman char *args; 336da59a31cSDavid Greenman int *retval; 337da59a31cSDavid Greenman { 338da59a31cSDavid Greenman int error = 0, i, n; 3390dbf6d73SJordan K. Hubbard int largest_ld; 340da59a31cSDavid Greenman struct pcb *pcb = &p->p_addr->u_pcb; 341da59a31cSDavid Greenman int s; 342da59a31cSDavid Greenman struct i386_set_ldt_args ua, *uap; 343da59a31cSDavid Greenman 344da59a31cSDavid Greenman if ((error = copyin(args, &ua, sizeof(struct i386_set_ldt_args))) < 0) 345da59a31cSDavid Greenman return(error); 346da59a31cSDavid Greenman 347da59a31cSDavid Greenman uap = &ua; 348da59a31cSDavid Greenman 349da59a31cSDavid Greenman #ifdef DEBUG 350da59a31cSDavid Greenman printf("i386_set_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc); 351da59a31cSDavid Greenman #endif 352da59a31cSDavid Greenman 3530dbf6d73SJordan K. Hubbard /* verify range of descriptors to modify */ 3548bb9c4c7SSteven Wallace if ((uap->start < 0) || (uap->start >= MAX_LD) || (uap->num < 0) || 3550dbf6d73SJordan K. Hubbard (uap->num > MAX_LD)) 3560dbf6d73SJordan K. Hubbard { 357da59a31cSDavid Greenman return(EINVAL); 3580dbf6d73SJordan K. Hubbard } 3590dbf6d73SJordan K. Hubbard largest_ld = uap->start + uap->num - 1; 3600dbf6d73SJordan K. Hubbard if (largest_ld >= MAX_LD) 361da59a31cSDavid Greenman return(EINVAL); 362da59a31cSDavid Greenman 363da59a31cSDavid Greenman /* allocate user ldt */ 3640dbf6d73SJordan K. Hubbard if (!pcb->pcb_ldt || (largest_ld >= pcb->pcb_ldt_len)) { 3650dbf6d73SJordan K. Hubbard union descriptor *new_ldt = (union descriptor *)kmem_alloc( 3660dbf6d73SJordan K. Hubbard kernel_map, SIZE_FROM_LARGEST_LD(largest_ld)); 3670dbf6d73SJordan K. Hubbard if (new_ldt == NULL) { 3680dbf6d73SJordan K. Hubbard return ENOMEM; 3690dbf6d73SJordan K. Hubbard } 3700dbf6d73SJordan K. Hubbard if (pcb->pcb_ldt) { 3710dbf6d73SJordan K. Hubbard bcopy(pcb->pcb_ldt, new_ldt, pcb->pcb_ldt_len 3720dbf6d73SJordan K. Hubbard * sizeof(union descriptor)); 3730dbf6d73SJordan K. Hubbard kmem_free(kernel_map, (vm_offset_t)pcb->pcb_ldt, 3740dbf6d73SJordan K. Hubbard pcb->pcb_ldt_len * sizeof(union descriptor)); 3750dbf6d73SJordan K. Hubbard } else { 376da59a31cSDavid Greenman bcopy(ldt, new_ldt, sizeof(ldt)); 3770dbf6d73SJordan K. Hubbard } 378da59a31cSDavid Greenman pcb->pcb_ldt = (caddr_t)new_ldt; 3790dbf6d73SJordan K. Hubbard pcb->pcb_ldt_len = NEW_MAX_LD(largest_ld); 3800dbf6d73SJordan K. Hubbard if (pcb == curpcb) 3810dbf6d73SJordan K. Hubbard set_user_ldt(pcb); 382da59a31cSDavid Greenman } 383da59a31cSDavid Greenman 384da59a31cSDavid Greenman /* Check descriptors for access violations */ 385da59a31cSDavid Greenman for (i = 0, n = uap->start; i < uap->num; i++, n++) { 386da59a31cSDavid Greenman union descriptor desc, *dp; 387da59a31cSDavid Greenman dp = &uap->desc[i]; 388da59a31cSDavid Greenman error = copyin(dp, &desc, sizeof(union descriptor)); 389da59a31cSDavid Greenman if (error) 390da59a31cSDavid Greenman return(error); 391da59a31cSDavid Greenman 3920dbf6d73SJordan K. Hubbard switch (desc.sd.sd_type) { 3930dbf6d73SJordan K. Hubbard case SDT_SYSNULL: /* system null */ 3940dbf6d73SJordan K. Hubbard desc.sd.sd_p = 0; 3950dbf6d73SJordan K. Hubbard break; 3960dbf6d73SJordan K. Hubbard case SDT_SYS286TSS: /* system 286 TSS available */ 3970dbf6d73SJordan K. Hubbard case SDT_SYSLDT: /* system local descriptor table */ 3980dbf6d73SJordan K. Hubbard case SDT_SYS286BSY: /* system 286 TSS busy */ 3990dbf6d73SJordan K. Hubbard case SDT_SYSTASKGT: /* system task gate */ 4000dbf6d73SJordan K. Hubbard case SDT_SYS286IGT: /* system 286 interrupt gate */ 4010dbf6d73SJordan K. Hubbard case SDT_SYS286TGT: /* system 286 trap gate */ 4020dbf6d73SJordan K. Hubbard case SDT_SYSNULL2: /* undefined by Intel */ 4030dbf6d73SJordan K. Hubbard case SDT_SYS386TSS: /* system 386 TSS available */ 4040dbf6d73SJordan K. Hubbard case SDT_SYSNULL3: /* undefined by Intel */ 4050dbf6d73SJordan K. Hubbard case SDT_SYS386BSY: /* system 386 TSS busy */ 4060dbf6d73SJordan K. Hubbard case SDT_SYSNULL4: /* undefined by Intel */ 4070dbf6d73SJordan K. Hubbard case SDT_SYS386IGT: /* system 386 interrupt gate */ 4080dbf6d73SJordan K. Hubbard case SDT_SYS386TGT: /* system 386 trap gate */ 4090dbf6d73SJordan K. Hubbard case SDT_SYS286CGT: /* system 286 call gate */ 4100dbf6d73SJordan K. Hubbard case SDT_SYS386CGT: /* system 386 call gate */ 4110dbf6d73SJordan K. Hubbard /* I can't think of any reason to allow a user proc 4120dbf6d73SJordan K. Hubbard * to create a segment of these types. They are 4130dbf6d73SJordan K. Hubbard * for OS use only. 4140dbf6d73SJordan K. Hubbard */ 4150dbf6d73SJordan K. Hubbard return EACCES; 416da59a31cSDavid Greenman 4170dbf6d73SJordan K. Hubbard /* memory segment types */ 4180dbf6d73SJordan K. Hubbard case SDT_MEMEC: /* memory execute only conforming */ 4190dbf6d73SJordan K. Hubbard case SDT_MEMEAC: /* memory execute only accessed conforming */ 4200dbf6d73SJordan K. Hubbard case SDT_MEMERC: /* memory execute read conforming */ 4210dbf6d73SJordan K. Hubbard case SDT_MEMERAC: /* memory execute read accessed conforming */ 4220dbf6d73SJordan K. Hubbard /* Must be "present" if executable and conforming. */ 423da59a31cSDavid Greenman if (desc.sd.sd_p == 0) 424da59a31cSDavid Greenman return (EACCES); 425da59a31cSDavid Greenman break; 4260dbf6d73SJordan K. Hubbard case SDT_MEMRO: /* memory read only */ 4270dbf6d73SJordan K. Hubbard case SDT_MEMROA: /* memory read only accessed */ 4280dbf6d73SJordan K. Hubbard case SDT_MEMRW: /* memory read write */ 4290dbf6d73SJordan K. Hubbard case SDT_MEMRWA: /* memory read write accessed */ 4300dbf6d73SJordan K. Hubbard case SDT_MEMROD: /* memory read only expand dwn limit */ 4310dbf6d73SJordan K. Hubbard case SDT_MEMRODA: /* memory read only expand dwn lim accessed */ 4320dbf6d73SJordan K. Hubbard case SDT_MEMRWD: /* memory read write expand dwn limit */ 4330dbf6d73SJordan K. Hubbard case SDT_MEMRWDA: /* memory read write expand dwn lim acessed */ 4340dbf6d73SJordan K. Hubbard case SDT_MEME: /* memory execute only */ 4350dbf6d73SJordan K. Hubbard case SDT_MEMEA: /* memory execute only accessed */ 4360dbf6d73SJordan K. Hubbard case SDT_MEMER: /* memory execute read */ 4370dbf6d73SJordan K. Hubbard case SDT_MEMERA: /* memory execute read accessed */ 438da59a31cSDavid Greenman break; 439da59a31cSDavid Greenman default: 4400dbf6d73SJordan K. Hubbard return(EINVAL); 441da59a31cSDavid Greenman /*NOTREACHED*/ 442da59a31cSDavid Greenman } 4430dbf6d73SJordan K. Hubbard 4440dbf6d73SJordan K. Hubbard /* Only user (ring-3) descriptors may be present. */ 4450dbf6d73SJordan K. Hubbard if ((desc.sd.sd_p != 0) && (desc.sd.sd_dpl != SEL_UPL)) 4460dbf6d73SJordan K. Hubbard return (EACCES); 447da59a31cSDavid Greenman } 448da59a31cSDavid Greenman 449da59a31cSDavid Greenman s = splhigh(); 450da59a31cSDavid Greenman 451da59a31cSDavid Greenman /* Fill in range */ 4520dbf6d73SJordan K. Hubbard error = copyin(uap->desc, 4530dbf6d73SJordan K. Hubbard &((union descriptor *)(pcb->pcb_ldt))[uap->start], 4540dbf6d73SJordan K. Hubbard uap->num * sizeof(union descriptor)); 4550dbf6d73SJordan K. Hubbard if (!error) 456da59a31cSDavid Greenman *retval = uap->start; 457da59a31cSDavid Greenman 458da59a31cSDavid Greenman splx(s); 459da59a31cSDavid Greenman return(error); 460da59a31cSDavid Greenman } 461da59a31cSDavid Greenman #endif /* USER_LDT */ 462