sys_machdep.c revision 1.1 1 /* $NetBSD: sys_machdep.c,v 1.1 2007/04/16 19:12:19 ad Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum, and by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.1 2007/04/16 19:12:19 ad Exp $");
41
42 #include "opt_compat_netbsd.h"
43 #include "opt_mtrr.h"
44 #include "opt_perfctrs.h"
45 #include "opt_user_ldt.h"
46 #include "opt_vm86.h"
47 #include "opt_xen.h"
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/ioctl.h>
52 #include <sys/file.h>
53 #include <sys/time.h>
54 #include <sys/proc.h>
55 #include <sys/user.h>
56 #include <sys/uio.h>
57 #include <sys/kernel.h>
58 #include <sys/buf.h>
59 #include <sys/signal.h>
60 #include <sys/malloc.h>
61 #include <sys/kauth.h>
62
63 #include <sys/mount.h>
64 #include <sys/syscallargs.h>
65
66 #include <uvm/uvm_extern.h>
67
68 #include <machine/cpu.h>
69 #include <machine/cpufunc.h>
70 #include <machine/gdt.h>
71 #include <machine/psl.h>
72 #include <machine/reg.h>
73 #include <machine/sysarch.h>
74 #include <machine/mtrr.h>
75
76 #ifdef __x86_64__
77 /* Need to be checked. */
78 #undef USER_LDT
79 #undef PERFCTRS
80 #undef VM86
81 #undef IOPERM
82 #else
83 #define IOPERM
84 #endif
85
86 #ifdef VM86
87 #include <machine/vm86.h>
88 #endif
89
90 #ifdef PERFCTRS
91 #include <machine/pmc.h>
92 #endif
93
94 extern struct vm_map *kernel_map;
95
96 int x86_get_ioperm(struct lwp *, void *, register_t *);
97 int x86_set_ioperm(struct lwp *, void *, register_t *);
98 int x86_get_mtrr(struct lwp *, void *, register_t *);
99 int x86_set_mtrr(struct lwp *, void *, register_t *);
100
101 #ifdef LDT_DEBUG
102 static void x86_print_ldt(int, const struct segment_descriptor *);
103
104 static void
105 x86_print_ldt(int i, const struct segment_descriptor *d)
106 {
107 printf("[%d] lolimit=0x%x, lobase=0x%x, type=%u, dpl=%u, p=%u, "
108 "hilimit=0x%x, xx=%x, def32=%u, gran=%u, hibase=0x%x\n",
109 i, d->sd_lolimit, d->sd_lobase, d->sd_type, d->sd_dpl, d->sd_p,
110 d->sd_hilimit, d->sd_xx, d->sd_def32, d->sd_gran, d->sd_hibase);
111 }
112 #endif
113
114 int
115 x86_get_ldt(struct lwp *l, void *args, register_t *retval)
116 {
117 #ifdef USER_LDT
118 int error;
119 struct proc *p = l->l_proc;
120 pmap_t pmap = p->p_vmspace->vm_map.pmap;
121 int nldt, num;
122 union descriptor *lp, *cp;
123 struct x86_get_ldt_args ua;
124
125 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_LDT_GET,
126 NULL, NULL, NULL, NULL);
127 if (error)
128 return (error);
129
130 if ((error = copyin(args, &ua, sizeof(ua))) != 0)
131 return (error);
132
133 #ifdef LDT_DEBUG
134 printf("x86_get_ldt: start=%d num=%d descs=%p\n", ua.start,
135 ua.num, ua.desc);
136 #endif
137
138 if (ua.start < 0 || ua.num < 0 || ua.start > 8192 || ua.num > 8192 ||
139 ua.start + ua.num > 8192)
140 return (EINVAL);
141
142 cp = malloc(ua.num * sizeof(union descriptor), M_TEMP, M_WAITOK);
143 if (cp == NULL)
144 return ENOMEM;
145
146 simple_lock(&pmap->pm_lock);
147
148 if (pmap->pm_flags & PMF_USER_LDT) {
149 nldt = pmap->pm_ldt_len;
150 lp = pmap->pm_ldt;
151 } else {
152 nldt = NLDT;
153 lp = ldt;
154 }
155
156 if (ua.start > nldt) {
157 simple_unlock(&pmap->pm_lock);
158 free(cp, M_TEMP);
159 return (EINVAL);
160 }
161
162 lp += ua.start;
163 num = min(ua.num, nldt - ua.start);
164 #ifdef LDT_DEBUG
165 {
166 int i;
167 for (i = 0; i < num; i++)
168 x86_print_ldt(i, &lp[i].sd);
169 }
170 #endif
171
172 memcpy(cp, lp, num * sizeof(union descriptor));
173 simple_unlock(&pmap->pm_lock);
174
175 error = copyout(cp, ua.desc, num * sizeof(union descriptor));
176 if (error == 0)
177 *retval = num;
178
179 free(cp, M_TEMP);
180 return (error);
181 #else
182 return EINVAL;
183 #endif
184 }
185
186 int
187 x86_set_ldt(struct lwp *l, void *args, register_t *retval)
188 {
189 #ifdef USER_LDT
190 int error, i, n, sel, free_sel;
191 struct proc *p = l->l_proc;
192 struct pcb *pcb = &l->l_addr->u_pcb;
193 pmap_t pmap = p->p_vmspace->vm_map.pmap;
194 struct x86_set_ldt_args ua;
195 union descriptor *descv;
196 size_t old_len, new_len, ldt_len, free_len;
197 union descriptor *old_ldt, *new_ldt, *free_ldt;
198
199 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_LDT_SET,
200 NULL, NULL, NULL, NULL);
201 if (error)
202 return (error);
203
204 if ((error = copyin(args, &ua, sizeof(ua))) != 0)
205 return (error);
206
207 if (ua.start < 0 || ua.num < 0 || ua.start > 8192 || ua.num > 8192 ||
208 ua.start + ua.num > 8192)
209 return (EINVAL);
210
211 descv = malloc(sizeof (*descv) * ua.num, M_TEMP, M_NOWAIT);
212 if (descv == NULL)
213 return (ENOMEM);
214
215 if ((error = copyin(ua.desc, descv, sizeof (*descv) * ua.num)) != 0)
216 goto out;
217
218 /* Check descriptors for access violations. */
219 for (i = 0; i < ua.num; i++) {
220 union descriptor *desc = &descv[i];
221
222 switch (desc->sd.sd_type) {
223 case SDT_SYSNULL:
224 desc->sd.sd_p = 0;
225 break;
226 case SDT_SYS286CGT:
227 case SDT_SYS386CGT:
228 /*
229 * Only allow call gates targeting a segment
230 * in the LDT or a user segment in the fixed
231 * part of the gdt. Segments in the LDT are
232 * constrained (below) to be user segments.
233 */
234 if (desc->gd.gd_p != 0 &&
235 !ISLDT(desc->gd.gd_selector) &&
236 ((IDXSEL(desc->gd.gd_selector) >= NGDT) ||
237 (gdt[IDXSEL(desc->gd.gd_selector)].sd.sd_dpl !=
238 SEL_UPL))) {
239 error = EACCES;
240 goto out;
241 }
242 break;
243 case SDT_MEMEC:
244 case SDT_MEMEAC:
245 case SDT_MEMERC:
246 case SDT_MEMERAC:
247 /* Must be "present" if executable and conforming. */
248 if (desc->sd.sd_p == 0) {
249 error = EACCES;
250 goto out;
251 }
252 break;
253 case SDT_MEMRO:
254 case SDT_MEMROA:
255 case SDT_MEMRW:
256 case SDT_MEMRWA:
257 case SDT_MEMROD:
258 case SDT_MEMRODA:
259 case SDT_MEMRWD:
260 case SDT_MEMRWDA:
261 case SDT_MEME:
262 case SDT_MEMEA:
263 case SDT_MEMER:
264 case SDT_MEMERA:
265 break;
266 default:
267 /*
268 * Make sure that unknown descriptor types are
269 * not marked present.
270 */
271 if (desc->sd.sd_p != 0) {
272 error = EACCES;
273 goto out;
274 }
275 break;
276 }
277
278 if (desc->sd.sd_p != 0) {
279 /* Only user (ring-3) descriptors may be present. */
280 if (desc->sd.sd_dpl != SEL_UPL) {
281 error = EACCES;
282 goto out;
283 }
284 }
285 }
286
287 /* allocate user ldt */
288 free_sel = -1;
289 new_ldt = NULL;
290 new_len = 0;
291 free_ldt = NULL;
292 free_len = 0;
293 simple_lock(&pmap->pm_lock);
294 if (pmap->pm_ldt == 0 || (ua.start + ua.num) > pmap->pm_ldt_len) {
295 if (pmap->pm_flags & PMF_USER_LDT)
296 ldt_len = pmap->pm_ldt_len;
297 else
298 ldt_len = 512;
299 while ((ua.start + ua.num) > ldt_len)
300 ldt_len *= 2;
301 new_len = ldt_len * sizeof(union descriptor);
302
303 simple_unlock(&pmap->pm_lock);
304 new_ldt = (union descriptor *)uvm_km_alloc(kernel_map,
305 new_len, 0, UVM_KMF_WIRED);
306 memset(new_ldt, 0, new_len);
307 sel = ldt_alloc(new_ldt, new_len);
308 simple_lock(&pmap->pm_lock);
309
310 if (pmap->pm_ldt != NULL && ldt_len <= pmap->pm_ldt_len) {
311 /*
312 * Another thread (re)allocated the LDT to
313 * sufficient size while we were blocked in
314 * uvm_km_alloc. Oh well. The new entries
315 * will quite probably not be right, but
316 * hey.. not our problem if user applications
317 * have race conditions like that.
318 */
319 goto copy;
320 }
321
322 old_ldt = pmap->pm_ldt;
323 free_ldt = old_ldt;
324 free_len = pmap->pm_ldt_len * sizeof(union descriptor);
325
326 if (old_ldt != NULL) {
327 old_len = pmap->pm_ldt_len * sizeof(union descriptor);
328 } else {
329 old_len = NLDT * sizeof(union descriptor);
330 old_ldt = ldt;
331 }
332
333 memcpy(new_ldt, old_ldt, old_len);
334 memset((char *)new_ldt + old_len, 0, new_len - old_len);
335
336 pmap->pm_ldt = new_ldt;
337 pmap->pm_ldt_len = ldt_len;
338
339 if (pmap->pm_flags & PMF_USER_LDT)
340 free_sel = pmap->pm_ldt_sel;
341 else {
342 pmap->pm_flags |= PMF_USER_LDT;
343 free_sel = -1;
344 }
345 pmap->pm_ldt_sel = sel;
346 pcb->pcb_ldt_sel = pmap->pm_ldt_sel;
347 if (pcb == curpcb)
348 lldt(pcb->pcb_ldt_sel);
349 new_ldt = NULL;
350 }
351 copy:
352 /* Now actually replace the descriptors. */
353 for (i = 0, n = ua.start; i < ua.num; i++, n++)
354 pmap->pm_ldt[n] = descv[i];
355
356 simple_unlock(&pmap->pm_lock);
357 *retval = ua.start;
358
359 if (new_ldt != NULL)
360 uvm_km_free(kernel_map, (vaddr_t)new_ldt, new_len,
361 UVM_KMF_WIRED);
362 if (free_sel != -1)
363 ldt_free(free_sel);
364 if (free_ldt != NULL)
365 uvm_km_free(kernel_map, (vaddr_t)free_ldt, free_len,
366 UVM_KMF_WIRED);
367 out:
368 free(descv, M_TEMP);
369 return (error);
370 #else
371 return EINVAL;
372 #endif
373 }
374
375 int
376 x86_iopl(struct lwp *l, void *args, register_t *retval)
377 {
378 int error;
379 struct x86_iopl_args ua;
380 #ifdef XEN
381 struct pcb *pcb = &l->l_addr->u_pcb;
382 #else
383 struct trapframe *tf = l->l_md.md_regs;
384 #endif
385
386 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPL,
387 NULL, NULL, NULL, NULL);
388 if (error)
389 return (error);
390
391 if ((error = copyin(args, &ua, sizeof(ua))) != 0)
392 return error;
393
394 #ifdef XEN
395 {
396 pcb->pcb_tss.tss_ioopt &= ~SEL_RPL;
397 if (ua.iopl)
398 pcb->pcb_tss.tss_ioopt |= SEL_UPL; /* i/o pl */
399 else
400 pcb->pcb_tss.tss_ioopt |= SEL_KPL; /* i/o pl */
401 }
402 /* Force the change at ring 0. */
403 #ifdef XEN3
404 {
405 struct physdev_op physop;
406 physop.cmd = PHYSDEVOP_SET_IOPL;
407 physop.u.set_iopl.iopl = pcb->pcb_tss.tss_ioopt & SEL_RPL;
408 HYPERVISOR_physdev_op(&physop);
409 }
410 #else /* XEN3 */
411 {
412 dom0_op_t op;
413 op.cmd = DOM0_IOPL;
414 op.u.iopl.domain = DOMID_SELF;
415 op.u.iopl.iopl = pcb->pcb_tss.tss_ioopt & SEL_RPL; /* i/o pl */
416 HYPERVISOR_dom0_op(&op);
417 }
418 #endif /* XEN3 */
419 #elif defined(__x86_64__)
420 if (ua.iopl)
421 tf->tf_rflags |= PSL_IOPL;
422 else
423 tf->tf_rflags &= ~PSL_IOPL;
424 #else
425 if (ua.iopl)
426 tf->tf_eflags |= PSL_IOPL;
427 else
428 tf->tf_eflags &= ~PSL_IOPL;
429 #endif
430
431 return 0;
432 }
433
434 int
435 x86_get_ioperm(struct lwp *l, void *args, register_t *retval)
436 {
437 #ifdef IOPERM
438 int error;
439 struct pcb *pcb = &l->l_addr->u_pcb;
440 struct x86_get_ioperm_args ua;
441
442 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPERM_GET,
443 NULL, NULL, NULL, NULL);
444 if (error)
445 return (error);
446
447 if ((error = copyin(args, &ua, sizeof(ua))) != 0)
448 return (error);
449
450 return copyout(pcb->pcb_iomap, ua.iomap, sizeof(pcb->pcb_iomap));
451 #else
452 return EINVAL;
453 #endif
454 }
455
456 int
457 x86_set_ioperm(struct lwp *l, void *args, register_t *retval)
458 {
459 #ifdef IOPERM
460 int error;
461 struct pcb *pcb = &l->l_addr->u_pcb;
462 struct x86_set_ioperm_args ua;
463
464 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPERM_SET,
465 NULL, NULL, NULL, NULL);
466 if (error)
467 return (error);
468
469 if ((error = copyin(args, &ua, sizeof(ua))) != 0)
470 return (error);
471
472 return copyin(ua.iomap, pcb->pcb_iomap, sizeof(pcb->pcb_iomap));
473 #else
474 return EINVAL;
475 #endif
476 }
477
478 int
479 x86_get_mtrr(struct lwp *l, void *args, register_t *retval)
480 {
481 #ifdef MTRR
482 struct x86_get_mtrr_args ua;
483 int error, n;
484
485 if (mtrr_funcs == NULL)
486 return ENOSYS;
487
488 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_MTRR_GET,
489 NULL, NULL, NULL, NULL);
490 if (error)
491 return (error);
492
493 error = copyin(args, &ua, sizeof ua);
494 if (error != 0)
495 return error;
496
497 error = copyin(ua.n, &n, sizeof n);
498 if (error != 0)
499 return error;
500
501 error = mtrr_get(ua.mtrrp, &n, l->l_proc, MTRR_GETSET_USER);
502
503 copyout(&n, ua.n, sizeof (int));
504
505 return error;
506 #else
507 return EINVAL;
508 #endif
509 }
510
511 int
512 x86_set_mtrr(struct lwp *l, void *args, register_t *retval)
513 {
514 #ifdef MTRR
515 int error, n;
516 struct x86_set_mtrr_args ua;
517
518 if (mtrr_funcs == NULL)
519 return ENOSYS;
520
521 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_MTRR_SET,
522 NULL, NULL, NULL, NULL);
523 if (error)
524 return (error);
525
526 error = copyin(args, &ua, sizeof ua);
527 if (error != 0)
528 return error;
529
530 error = copyin(ua.n, &n, sizeof n);
531 if (error != 0)
532 return error;
533
534 error = mtrr_set(ua.mtrrp, &n, l->l_proc, MTRR_GETSET_USER);
535 if (n != 0)
536 mtrr_commit();
537
538 copyout(&n, ua.n, sizeof n);
539
540 return error;
541 #else
542 return EINVAL;
543 #endif
544 }
545
546 int
547 sys_sysarch(struct lwp *l, void *v, register_t *retval)
548 {
549 struct sys_sysarch_args /* {
550 syscallarg(int) op;
551 syscallarg(void *) parms;
552 } */ *uap = v;
553 int error = 0;
554
555 switch(SCARG(uap, op)) {
556 case X86_IOPL:
557 error = x86_iopl(l, SCARG(uap, parms), retval);
558 break;
559
560 case X86_GET_LDT:
561 error = x86_get_ldt(l, SCARG(uap, parms), retval);
562 break;
563
564 case X86_SET_LDT:
565 error = x86_set_ldt(l, SCARG(uap, parms), retval);
566 break;
567
568 case X86_GET_IOPERM:
569 error = x86_get_ioperm(l, SCARG(uap, parms), retval);
570 break;
571
572 case X86_SET_IOPERM:
573 error = x86_set_ioperm(l, SCARG(uap, parms), retval);
574 break;
575
576 case X86_GET_MTRR:
577 error = x86_get_mtrr(l, SCARG(uap, parms), retval);
578 break;
579 case X86_SET_MTRR:
580 error = x86_set_mtrr(l, SCARG(uap, parms), retval);
581 break;
582
583 #ifdef VM86
584 case X86_VM86:
585 error = x86_vm86(l, SCARG(uap, parms), retval);
586 break;
587 #ifdef COMPAT_16
588 case X86_OLD_VM86:
589 error = compat_16_x86_vm86(l, SCARG(uap, parms), retval);
590 break;
591 #endif
592 #endif
593
594 #ifdef PERFCTRS
595 case X86_PMC_INFO:
596 error = pmc_info(l, SCARG(uap, parms), retval);
597 break;
598
599 case X86_PMC_STARTSTOP:
600 error = pmc_startstop(l, SCARG(uap, parms), retval);
601 break;
602
603 case X86_PMC_READ:
604 error = pmc_read(l, SCARG(uap, parms), retval);
605 break;
606 #endif
607
608 default:
609 error = EINVAL;
610 break;
611 }
612 return (error);
613 }
614