xref: /freebsd/sys/i386/i386/sys_machdep.c (revision 8bb9c4c7)
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