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
|