sys_machdep.c revision 1.2 1 /* $NetBSD: sys_machdep.c,v 1.2 2007/06/23 15:22:18 dsl 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.2 2007/06/23 15:22:18 dsl 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_len(struct lwp *l)
116 {
117 #ifndef USER_LDT
118 return -1;
119 #else
120 pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap;
121 int nldt;
122
123 simple_lock(&pmap->pm_lock);
124
125 if (pmap->pm_flags & PMF_USER_LDT) {
126 nldt = pmap->pm_ldt_len;
127 } else {
128 nldt = NLDT;
129 }
130 simple_unlock(&pmap->pm_lock);
131 return nldt;
132 #endif
133 }
134
135
136 int
137 x86_get_ldt(struct lwp *l, void *args, register_t *retval)
138 {
139 #ifndef USER_LDT
140 return EINVAL;
141 #else
142 struct x86_get_ldt_args ua;
143 union descriptor *cp;
144 int error;
145
146 if ((error = copyin(args, &ua, sizeof(ua))) != 0)
147 return error;
148
149 if (ua.num < 0 || ua.num > 8192)
150 return EINVAL;
151
152 cp = malloc(ua.num * sizeof(union descriptor), M_TEMP, M_WAITOK);
153 if (cp == NULL)
154 return ENOMEM;
155
156 error = x86_get_ldt1(l, &ua, cp);
157 *retval = ua.num;
158 if (error == 0)
159 error = copyout(cp, ua.desc, ua.num * sizeof(*cp));
160
161 free(cp, M_TEMP);
162 return error;
163 #endif
164 }
165
166 int
167 x86_get_ldt1(struct lwp *l, struct x86_get_ldt_args *ua, union descriptor *cp)
168 {
169 #ifndef USER_LDT
170 return EINVAL;
171 #else
172 int error;
173 struct proc *p = l->l_proc;
174 pmap_t pmap = p->p_vmspace->vm_map.pmap;
175 int nldt, num;
176 union descriptor *lp;
177
178 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_LDT_GET,
179 NULL, NULL, NULL, NULL);
180 if (error)
181 return (error);
182
183 #ifdef LDT_DEBUG
184 printf("x86_get_ldt: start=%d num=%d descs=%p\n", ua->start,
185 ua->num, ua->desc);
186 #endif
187
188 if (ua->start < 0 || ua->num < 0 || ua->start > 8192 || ua->num > 8192 ||
189 ua->start + ua->num > 8192)
190 return (EINVAL);
191
192 simple_lock(&pmap->pm_lock);
193
194 if (pmap->pm_flags & PMF_USER_LDT) {
195 nldt = pmap->pm_ldt_len;
196 lp = pmap->pm_ldt;
197 } else {
198 nldt = NLDT;
199 lp = ldt;
200 }
201
202 if (ua->start > nldt) {
203 simple_unlock(&pmap->pm_lock);
204 return (EINVAL);
205 }
206
207 lp += ua->start;
208 num = min(ua->num, nldt - ua->start);
209 ua->num = num;
210 #ifdef LDT_DEBUG
211 {
212 int i;
213 for (i = 0; i < num; i++)
214 x86_print_ldt(i, &lp[i].sd);
215 }
216 #endif
217
218 memcpy(cp, lp, num * sizeof(union descriptor));
219 simple_unlock(&pmap->pm_lock);
220
221 return 0;
222 #endif
223 }
224
225 int
226 x86_set_ldt(struct lwp *l, void *args, register_t *retval)
227 {
228 #ifndef USER_LDT
229 return EINVAL;
230 #else
231 struct x86_set_ldt_args ua;
232 union descriptor *descv;
233 int error;
234
235 if ((error = copyin(args, &ua, sizeof(ua))) != 0)
236 return (error);
237
238 if (ua.num < 0 || ua.num > 8192)
239 return EINVAL;
240
241 descv = malloc(sizeof (*descv) * ua.num, M_TEMP, M_NOWAIT);
242 if (descv == NULL)
243 return ENOMEM;
244
245 error = copyin(ua.desc, descv, sizeof (*descv) * ua.num);
246 if (error == 0)
247 error = x86_set_ldt1(l, &ua, descv);
248 *retval = ua.start;
249
250 free(descv, M_TEMP);
251 return error;
252 #endif
253 }
254
255 int
256 x86_set_ldt1(struct lwp *l, struct x86_set_ldt_args *ua,
257 union descriptor *descv)
258 {
259 #ifndef USER_LDT
260 return EINVAL;
261 #else
262 int error, i, n, sel, free_sel;
263 struct proc *p = l->l_proc;
264 struct pcb *pcb = &l->l_addr->u_pcb;
265 pmap_t pmap = p->p_vmspace->vm_map.pmap;
266 size_t old_len, new_len, ldt_len, free_len;
267 union descriptor *old_ldt, *new_ldt, *free_ldt;
268
269 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_LDT_SET,
270 NULL, NULL, NULL, NULL);
271 if (error)
272 return (error);
273
274 if (ua->start < 0 || ua->num < 0 || ua->start > 8192 || ua->num > 8192 ||
275 ua->start + ua->num > 8192)
276 return (EINVAL);
277
278 /* Check descriptors for access violations. */
279 for (i = 0; i < ua->num; i++) {
280 union descriptor *desc = &descv[i];
281
282 switch (desc->sd.sd_type) {
283 case SDT_SYSNULL:
284 desc->sd.sd_p = 0;
285 break;
286 case SDT_SYS286CGT:
287 case SDT_SYS386CGT:
288 /*
289 * Only allow call gates targeting a segment
290 * in the LDT or a user segment in the fixed
291 * part of the gdt. Segments in the LDT are
292 * constrained (below) to be user segments.
293 */
294 if (desc->gd.gd_p != 0 &&
295 !ISLDT(desc->gd.gd_selector) &&
296 ((IDXSEL(desc->gd.gd_selector) >= NGDT) ||
297 (gdt[IDXSEL(desc->gd.gd_selector)].sd.sd_dpl !=
298 SEL_UPL))) {
299 return EACCES;
300 }
301 break;
302 case SDT_MEMEC:
303 case SDT_MEMEAC:
304 case SDT_MEMERC:
305 case SDT_MEMERAC:
306 /* Must be "present" if executable and conforming. */
307 if (desc->sd.sd_p == 0)
308 return EACCES;
309 break;
310 case SDT_MEMRO:
311 case SDT_MEMROA:
312 case SDT_MEMRW:
313 case SDT_MEMRWA:
314 case SDT_MEMROD:
315 case SDT_MEMRODA:
316 case SDT_MEMRWD:
317 case SDT_MEMRWDA:
318 case SDT_MEME:
319 case SDT_MEMEA:
320 case SDT_MEMER:
321 case SDT_MEMERA:
322 break;
323 default:
324 /*
325 * Make sure that unknown descriptor types are
326 * not marked present.
327 */
328 if (desc->sd.sd_p != 0)
329 return EACCES;
330 break;
331 }
332
333 if (desc->sd.sd_p != 0) {
334 /* Only user (ring-3) descriptors may be present. */
335 if (desc->sd.sd_dpl != SEL_UPL)
336 return EACCES;
337 }
338 }
339
340 /* allocate user ldt */
341 free_sel = -1;
342 new_ldt = NULL;
343 new_len = 0;
344 free_ldt = NULL;
345 free_len = 0;
346 simple_lock(&pmap->pm_lock);
347 if (pmap->pm_ldt == 0 || (ua->start + ua->num) > pmap->pm_ldt_len) {
348 if (pmap->pm_flags & PMF_USER_LDT)
349 ldt_len = pmap->pm_ldt_len;
350 else
351 ldt_len = 512;
352 while ((ua->start + ua->num) > ldt_len)
353 ldt_len *= 2;
354 new_len = ldt_len * sizeof(union descriptor);
355
356 simple_unlock(&pmap->pm_lock);
357 new_ldt = (union descriptor *)uvm_km_alloc(kernel_map,
358 new_len, 0, UVM_KMF_WIRED);
359 memset(new_ldt, 0, new_len);
360 sel = ldt_alloc(new_ldt, new_len);
361 simple_lock(&pmap->pm_lock);
362
363 if (pmap->pm_ldt != NULL && ldt_len <= pmap->pm_ldt_len) {
364 /*
365 * Another thread (re)allocated the LDT to
366 * sufficient size while we were blocked in
367 * uvm_km_alloc. Oh well. The new entries
368 * will quite probably not be right, but
369 * hey.. not our problem if user applications
370 * have race conditions like that.
371 */
372 goto copy;
373 }
374
375 old_ldt = pmap->pm_ldt;
376 free_ldt = old_ldt;
377 free_len = pmap->pm_ldt_len * sizeof(union descriptor);
378
379 if (old_ldt != NULL) {
380 old_len = pmap->pm_ldt_len * sizeof(union descriptor);
381 } else {
382 old_len = NLDT * sizeof(union descriptor);
383 old_ldt = ldt;
384 }
385
386 memcpy(new_ldt, old_ldt, old_len);
387 memset((char *)new_ldt + old_len, 0, new_len - old_len);
388
389 pmap->pm_ldt = new_ldt;
390 pmap->pm_ldt_len = ldt_len;
391
392 if (pmap->pm_flags & PMF_USER_LDT)
393 free_sel = pmap->pm_ldt_sel;
394 else {
395 pmap->pm_flags |= PMF_USER_LDT;
396 free_sel = -1;
397 }
398 pmap->pm_ldt_sel = sel;
399 pcb->pcb_ldt_sel = pmap->pm_ldt_sel;
400 if (pcb == curpcb)
401 lldt(pcb->pcb_ldt_sel);
402 new_ldt = NULL;
403 }
404 copy:
405 /* Now actually replace the descriptors. */
406 for (i = 0, n = ua->start; i < ua->num; i++, n++)
407 pmap->pm_ldt[n] = descv[i];
408
409 simple_unlock(&pmap->pm_lock);
410
411 if (new_ldt != NULL)
412 uvm_km_free(kernel_map, (vaddr_t)new_ldt, new_len,
413 UVM_KMF_WIRED);
414 if (free_sel != -1)
415 ldt_free(free_sel);
416 if (free_ldt != NULL)
417 uvm_km_free(kernel_map, (vaddr_t)free_ldt, free_len,
418 UVM_KMF_WIRED);
419
420 return (error);
421 #endif
422 }
423
424 int
425 x86_iopl(struct lwp *l, void *args, register_t *retval)
426 {
427 int error;
428 struct x86_iopl_args ua;
429 #ifdef XEN
430 struct pcb *pcb = &l->l_addr->u_pcb;
431 #else
432 struct trapframe *tf = l->l_md.md_regs;
433 #endif
434
435 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPL,
436 NULL, NULL, NULL, NULL);
437 if (error)
438 return (error);
439
440 if ((error = copyin(args, &ua, sizeof(ua))) != 0)
441 return error;
442
443 #ifdef XEN
444 {
445 pcb->pcb_tss.tss_ioopt &= ~SEL_RPL;
446 if (ua.iopl)
447 pcb->pcb_tss.tss_ioopt |= SEL_UPL; /* i/o pl */
448 else
449 pcb->pcb_tss.tss_ioopt |= SEL_KPL; /* i/o pl */
450 }
451 /* Force the change at ring 0. */
452 #ifdef XEN3
453 {
454 struct physdev_op physop;
455 physop.cmd = PHYSDEVOP_SET_IOPL;
456 physop.u.set_iopl.iopl = pcb->pcb_tss.tss_ioopt & SEL_RPL;
457 HYPERVISOR_physdev_op(&physop);
458 }
459 #else /* XEN3 */
460 {
461 dom0_op_t op;
462 op.cmd = DOM0_IOPL;
463 op.u.iopl.domain = DOMID_SELF;
464 op.u.iopl.iopl = pcb->pcb_tss.tss_ioopt & SEL_RPL; /* i/o pl */
465 HYPERVISOR_dom0_op(&op);
466 }
467 #endif /* XEN3 */
468 #elif defined(__x86_64__)
469 if (ua.iopl)
470 tf->tf_rflags |= PSL_IOPL;
471 else
472 tf->tf_rflags &= ~PSL_IOPL;
473 #else
474 if (ua.iopl)
475 tf->tf_eflags |= PSL_IOPL;
476 else
477 tf->tf_eflags &= ~PSL_IOPL;
478 #endif
479
480 return 0;
481 }
482
483 int
484 x86_get_ioperm(struct lwp *l, void *args, register_t *retval)
485 {
486 #ifdef IOPERM
487 int error;
488 struct pcb *pcb = &l->l_addr->u_pcb;
489 struct x86_get_ioperm_args ua;
490
491 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPERM_GET,
492 NULL, NULL, NULL, NULL);
493 if (error)
494 return (error);
495
496 if ((error = copyin(args, &ua, sizeof(ua))) != 0)
497 return (error);
498
499 return copyout(pcb->pcb_iomap, ua.iomap, sizeof(pcb->pcb_iomap));
500 #else
501 return EINVAL;
502 #endif
503 }
504
505 int
506 x86_set_ioperm(struct lwp *l, void *args, register_t *retval)
507 {
508 #ifdef IOPERM
509 int error;
510 struct pcb *pcb = &l->l_addr->u_pcb;
511 struct x86_set_ioperm_args ua;
512
513 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPERM_SET,
514 NULL, NULL, NULL, NULL);
515 if (error)
516 return (error);
517
518 if ((error = copyin(args, &ua, sizeof(ua))) != 0)
519 return (error);
520
521 return copyin(ua.iomap, pcb->pcb_iomap, sizeof(pcb->pcb_iomap));
522 #else
523 return EINVAL;
524 #endif
525 }
526
527 int
528 x86_get_mtrr(struct lwp *l, void *args, register_t *retval)
529 {
530 #ifdef MTRR
531 struct x86_get_mtrr_args ua;
532 int error, n;
533
534 if (mtrr_funcs == NULL)
535 return ENOSYS;
536
537 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_MTRR_GET,
538 NULL, NULL, NULL, NULL);
539 if (error)
540 return (error);
541
542 error = copyin(args, &ua, sizeof ua);
543 if (error != 0)
544 return error;
545
546 error = copyin(ua.n, &n, sizeof n);
547 if (error != 0)
548 return error;
549
550 error = mtrr_get(ua.mtrrp, &n, l->l_proc, MTRR_GETSET_USER);
551
552 copyout(&n, ua.n, sizeof (int));
553
554 return error;
555 #else
556 return EINVAL;
557 #endif
558 }
559
560 int
561 x86_set_mtrr(struct lwp *l, void *args, register_t *retval)
562 {
563 #ifdef MTRR
564 int error, n;
565 struct x86_set_mtrr_args ua;
566
567 if (mtrr_funcs == NULL)
568 return ENOSYS;
569
570 error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_MTRR_SET,
571 NULL, NULL, NULL, NULL);
572 if (error)
573 return (error);
574
575 error = copyin(args, &ua, sizeof ua);
576 if (error != 0)
577 return error;
578
579 error = copyin(ua.n, &n, sizeof n);
580 if (error != 0)
581 return error;
582
583 error = mtrr_set(ua.mtrrp, &n, l->l_proc, MTRR_GETSET_USER);
584 if (n != 0)
585 mtrr_commit();
586
587 copyout(&n, ua.n, sizeof n);
588
589 return error;
590 #else
591 return EINVAL;
592 #endif
593 }
594
595 int
596 sys_sysarch(struct lwp *l, void *v, register_t *retval)
597 {
598 struct sys_sysarch_args /* {
599 syscallarg(int) op;
600 syscallarg(void *) parms;
601 } */ *uap = v;
602 int error = 0;
603
604 switch(SCARG(uap, op)) {
605 case X86_IOPL:
606 error = x86_iopl(l, SCARG(uap, parms), retval);
607 break;
608
609 case X86_GET_LDT:
610 error = x86_get_ldt(l, SCARG(uap, parms), retval);
611 break;
612
613 case X86_SET_LDT:
614 error = x86_set_ldt(l, SCARG(uap, parms), retval);
615 break;
616
617 case X86_GET_IOPERM:
618 error = x86_get_ioperm(l, SCARG(uap, parms), retval);
619 break;
620
621 case X86_SET_IOPERM:
622 error = x86_set_ioperm(l, SCARG(uap, parms), retval);
623 break;
624
625 case X86_GET_MTRR:
626 error = x86_get_mtrr(l, SCARG(uap, parms), retval);
627 break;
628 case X86_SET_MTRR:
629 error = x86_set_mtrr(l, SCARG(uap, parms), retval);
630 break;
631
632 #ifdef VM86
633 case X86_VM86:
634 error = x86_vm86(l, SCARG(uap, parms), retval);
635 break;
636 #ifdef COMPAT_16
637 case X86_OLD_VM86:
638 error = compat_16_x86_vm86(l, SCARG(uap, parms), retval);
639 break;
640 #endif
641 #endif
642
643 #ifdef PERFCTRS
644 case X86_PMC_INFO:
645 error = pmc_info(l, SCARG(uap, parms), retval);
646 break;
647
648 case X86_PMC_STARTSTOP:
649 error = pmc_startstop(l, SCARG(uap, parms), retval);
650 break;
651
652 case X86_PMC_READ:
653 error = pmc_read(l, SCARG(uap, parms), retval);
654 break;
655 #endif
656
657 default:
658 error = EINVAL;
659 break;
660 }
661 return (error);
662 }
663