1 | /* $NetBSD: sys_machdep.c,v 1.30 2016/09/24 21:13:44 dholland Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1998, 2007, 2009 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 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.30 2016/09/24 21:13:44 dholland Exp $" ); |
34 | |
35 | #include "opt_mtrr.h" |
36 | #include "opt_perfctrs.h" |
37 | #include "opt_user_ldt.h" |
38 | #include "opt_compat_netbsd.h" |
39 | #ifdef i386 |
40 | #include "opt_vm86.h" |
41 | #endif |
42 | #include "opt_xen.h" |
43 | |
44 | #include <sys/param.h> |
45 | #include <sys/systm.h> |
46 | #include <sys/ioctl.h> |
47 | #include <sys/file.h> |
48 | #include <sys/time.h> |
49 | #include <sys/proc.h> |
50 | #include <sys/uio.h> |
51 | #include <sys/kernel.h> |
52 | #include <sys/buf.h> |
53 | #include <sys/signal.h> |
54 | #include <sys/malloc.h> |
55 | #include <sys/kmem.h> |
56 | #include <sys/kauth.h> |
57 | #include <sys/cpu.h> |
58 | #include <sys/mount.h> |
59 | #include <sys/syscallargs.h> |
60 | |
61 | #include <uvm/uvm_extern.h> |
62 | |
63 | #include <machine/cpufunc.h> |
64 | #include <machine/gdt.h> |
65 | #include <machine/psl.h> |
66 | #include <machine/reg.h> |
67 | #include <machine/sysarch.h> |
68 | #include <machine/mtrr.h> |
69 | |
70 | #ifdef __x86_64__ |
71 | /* Need to be checked. */ |
72 | #undef USER_LDT |
73 | #undef PERFCTRS |
74 | #undef IOPERM |
75 | #else |
76 | #if defined(XEN) |
77 | #undef IOPERM |
78 | #else /* defined(XEN) */ |
79 | #define IOPERM |
80 | #endif /* defined(XEN) */ |
81 | #endif |
82 | |
83 | #ifdef VM86 |
84 | #include <machine/vm86.h> |
85 | #endif |
86 | |
87 | #ifdef PERFCTRS |
88 | #include <machine/pmc.h> |
89 | #endif |
90 | |
91 | extern struct vm_map *kernel_map; |
92 | |
93 | int x86_get_ioperm(struct lwp *, void *, register_t *); |
94 | int x86_set_ioperm(struct lwp *, void *, register_t *); |
95 | int x86_get_mtrr(struct lwp *, void *, register_t *); |
96 | int x86_set_mtrr(struct lwp *, void *, register_t *); |
97 | int x86_set_sdbase32(void *, char, lwp_t *, bool); |
98 | int x86_set_sdbase(void *, char, lwp_t *, bool); |
99 | int x86_get_sdbase32(void *, char); |
100 | int x86_get_sdbase(void *, char); |
101 | |
102 | #if defined(USER_LDT) && defined(LDT_DEBUG) |
103 | static void x86_print_ldt(int, const struct segment_descriptor *); |
104 | |
105 | static void |
106 | x86_print_ldt(int i, const struct segment_descriptor *d) |
107 | { |
108 | printf("[%d] lolimit=0x%x, lobase=0x%x, type=%u, dpl=%u, p=%u, " |
109 | "hilimit=0x%x, xx=%x, def32=%u, gran=%u, hibase=0x%x\n" , |
110 | i, d->sd_lolimit, d->sd_lobase, d->sd_type, d->sd_dpl, d->sd_p, |
111 | d->sd_hilimit, d->sd_xx, d->sd_def32, d->sd_gran, d->sd_hibase); |
112 | } |
113 | #endif |
114 | |
115 | int |
116 | x86_get_ldt(struct lwp *l, void *args, register_t *retval) |
117 | { |
118 | #ifndef USER_LDT |
119 | return EINVAL; |
120 | #else |
121 | struct x86_get_ldt_args ua; |
122 | union descriptor *cp; |
123 | int error; |
124 | |
125 | if ((error = copyin(args, &ua, sizeof(ua))) != 0) |
126 | return error; |
127 | |
128 | if (ua.num < 0 || ua.num > 8192) |
129 | return EINVAL; |
130 | |
131 | cp = malloc(ua.num * sizeof(union descriptor), M_TEMP, M_WAITOK); |
132 | if (cp == NULL) |
133 | return ENOMEM; |
134 | |
135 | error = x86_get_ldt1(l, &ua, cp); |
136 | *retval = ua.num; |
137 | if (error == 0) |
138 | error = copyout(cp, ua.desc, ua.num * sizeof(*cp)); |
139 | |
140 | free(cp, M_TEMP); |
141 | return error; |
142 | #endif |
143 | } |
144 | |
145 | int |
146 | x86_get_ldt1(struct lwp *l, struct x86_get_ldt_args *ua, union descriptor *cp) |
147 | { |
148 | #ifndef USER_LDT |
149 | return EINVAL; |
150 | #else |
151 | int error; |
152 | struct proc *p = l->l_proc; |
153 | pmap_t pmap = p->p_vmspace->vm_map.pmap; |
154 | int nldt, num; |
155 | union descriptor *lp; |
156 | |
157 | error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_LDT_GET, |
158 | NULL, NULL, NULL, NULL); |
159 | if (error) |
160 | return (error); |
161 | |
162 | #ifdef LDT_DEBUG |
163 | printf("x86_get_ldt: start=%d num=%d descs=%p\n" , ua->start, |
164 | ua->num, ua->desc); |
165 | #endif |
166 | |
167 | if (ua->start < 0 || ua->num < 0 || ua->start > 8192 || ua->num > 8192 || |
168 | ua->start + ua->num > 8192) |
169 | return (EINVAL); |
170 | |
171 | mutex_enter(&cpu_lock); |
172 | |
173 | if (pmap->pm_ldt != NULL) { |
174 | nldt = pmap->pm_ldt_len / sizeof(*lp); |
175 | lp = pmap->pm_ldt; |
176 | } else { |
177 | nldt = NLDT; |
178 | lp = ldt; |
179 | } |
180 | |
181 | if (ua->start > nldt) { |
182 | mutex_exit(&cpu_lock); |
183 | return (EINVAL); |
184 | } |
185 | |
186 | lp += ua->start; |
187 | num = min(ua->num, nldt - ua->start); |
188 | ua->num = num; |
189 | #ifdef LDT_DEBUG |
190 | { |
191 | int i; |
192 | for (i = 0; i < num; i++) |
193 | x86_print_ldt(i, &lp[i].sd); |
194 | } |
195 | #endif |
196 | |
197 | memcpy(cp, lp, num * sizeof(union descriptor)); |
198 | mutex_exit(&cpu_lock); |
199 | |
200 | return 0; |
201 | #endif |
202 | } |
203 | |
204 | int |
205 | x86_set_ldt(struct lwp *l, void *args, register_t *retval) |
206 | { |
207 | #ifndef USER_LDT |
208 | return EINVAL; |
209 | #else |
210 | struct x86_set_ldt_args ua; |
211 | union descriptor *descv; |
212 | int error; |
213 | |
214 | if ((error = copyin(args, &ua, sizeof(ua))) != 0) |
215 | return (error); |
216 | |
217 | if (ua.num < 0 || ua.num > 8192) |
218 | return EINVAL; |
219 | |
220 | descv = malloc(sizeof (*descv) * ua.num, M_TEMP, M_NOWAIT); |
221 | if (descv == NULL) |
222 | return ENOMEM; |
223 | |
224 | error = copyin(ua.desc, descv, sizeof (*descv) * ua.num); |
225 | if (error == 0) |
226 | error = x86_set_ldt1(l, &ua, descv); |
227 | *retval = ua.start; |
228 | |
229 | free(descv, M_TEMP); |
230 | return error; |
231 | #endif |
232 | } |
233 | |
234 | int |
235 | x86_set_ldt1(struct lwp *l, struct x86_set_ldt_args *ua, |
236 | union descriptor *descv) |
237 | { |
238 | #ifndef USER_LDT |
239 | return EINVAL; |
240 | #else |
241 | int error, i, n, old_sel, new_sel; |
242 | struct proc *p = l->l_proc; |
243 | pmap_t pmap = p->p_vmspace->vm_map.pmap; |
244 | size_t old_len, new_len; |
245 | union descriptor *old_ldt, *new_ldt; |
246 | |
247 | error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_LDT_SET, |
248 | NULL, NULL, NULL, NULL); |
249 | if (error) |
250 | return (error); |
251 | |
252 | if (ua->start < 0 || ua->num < 0 || ua->start > 8192 || ua->num > 8192 || |
253 | ua->start + ua->num > 8192) |
254 | return (EINVAL); |
255 | |
256 | /* Check descriptors for access violations. */ |
257 | for (i = 0; i < ua->num; i++) { |
258 | union descriptor *desc = &descv[i]; |
259 | |
260 | switch (desc->sd.sd_type) { |
261 | case SDT_SYSNULL: |
262 | desc->sd.sd_p = 0; |
263 | break; |
264 | case SDT_SYS286CGT: |
265 | case SDT_SYS386CGT: |
266 | /* |
267 | * Only allow call gates targeting a segment |
268 | * in the LDT or a user segment in the fixed |
269 | * part of the gdt. Segments in the LDT are |
270 | * constrained (below) to be user segments. |
271 | */ |
272 | if (desc->gd.gd_p != 0 && |
273 | !ISLDT(desc->gd.gd_selector) && |
274 | ((IDXSEL(desc->gd.gd_selector) >= NGDT) || |
275 | (gdt[IDXSEL(desc->gd.gd_selector)].sd.sd_dpl != |
276 | SEL_UPL))) { |
277 | return EACCES; |
278 | } |
279 | break; |
280 | case SDT_MEMEC: |
281 | case SDT_MEMEAC: |
282 | case SDT_MEMERC: |
283 | case SDT_MEMERAC: |
284 | /* Must be "present" if executable and conforming. */ |
285 | if (desc->sd.sd_p == 0) |
286 | return EACCES; |
287 | break; |
288 | case SDT_MEMRO: |
289 | case SDT_MEMROA: |
290 | case SDT_MEMRW: |
291 | case SDT_MEMRWA: |
292 | case SDT_MEMROD: |
293 | case SDT_MEMRODA: |
294 | case SDT_MEMRWD: |
295 | case SDT_MEMRWDA: |
296 | case SDT_MEME: |
297 | case SDT_MEMEA: |
298 | case SDT_MEMER: |
299 | case SDT_MEMERA: |
300 | break; |
301 | default: |
302 | /* |
303 | * Make sure that unknown descriptor types are |
304 | * not marked present. |
305 | */ |
306 | if (desc->sd.sd_p != 0) |
307 | return EACCES; |
308 | break; |
309 | } |
310 | |
311 | if (desc->sd.sd_p != 0) { |
312 | /* Only user (ring-3) descriptors may be present. */ |
313 | if (desc->sd.sd_dpl != SEL_UPL) |
314 | return EACCES; |
315 | } |
316 | } |
317 | |
318 | /* |
319 | * Install selected changes. We perform a copy, write, swap dance |
320 | * here to ensure that all updates happen atomically. |
321 | */ |
322 | |
323 | /* Allocate a new LDT. */ |
324 | for (;;) { |
325 | new_len = (ua->start + ua->num) * sizeof(union descriptor); |
326 | new_len = max(new_len, pmap->pm_ldt_len); |
327 | new_len = max(new_len, NLDT * sizeof(union descriptor)); |
328 | new_len = round_page(new_len); |
329 | new_ldt = (union descriptor *)uvm_km_alloc(kernel_map, |
330 | new_len, 0, UVM_KMF_WIRED | UVM_KMF_ZERO | UVM_KMF_WAITVA); |
331 | mutex_enter(&cpu_lock); |
332 | if (pmap->pm_ldt_len <= new_len) { |
333 | break; |
334 | } |
335 | mutex_exit(&cpu_lock); |
336 | uvm_km_free(kernel_map, (vaddr_t)new_ldt, new_len, |
337 | UVM_KMF_WIRED); |
338 | } |
339 | |
340 | /* Copy existing entries, if any. */ |
341 | if (pmap->pm_ldt != NULL) { |
342 | old_ldt = pmap->pm_ldt; |
343 | old_len = pmap->pm_ldt_len; |
344 | old_sel = pmap->pm_ldt_sel; |
345 | memcpy(new_ldt, old_ldt, old_len); |
346 | } else { |
347 | old_ldt = NULL; |
348 | old_len = 0; |
349 | old_sel = -1; |
350 | memcpy(new_ldt, ldt, NLDT * sizeof(union descriptor)); |
351 | } |
352 | |
353 | /* Apply requested changes. */ |
354 | for (i = 0, n = ua->start; i < ua->num; i++, n++) { |
355 | new_ldt[n] = descv[i]; |
356 | } |
357 | |
358 | /* Allocate LDT selector. */ |
359 | new_sel = ldt_alloc(new_ldt, new_len); |
360 | if (new_sel == -1) { |
361 | mutex_exit(&cpu_lock); |
362 | uvm_km_free(kernel_map, (vaddr_t)new_ldt, new_len, |
363 | UVM_KMF_WIRED); |
364 | return ENOMEM; |
365 | } |
366 | |
367 | /* All changes are now globally visible. Swap in the new LDT. */ |
368 | pmap->pm_ldt_len = new_len; |
369 | pmap->pm_ldt_sel = new_sel; |
370 | /* membar_store_store for pmap_fork() to read these unlocked safely */ |
371 | membar_producer(); |
372 | pmap->pm_ldt = new_ldt; |
373 | |
374 | /* Switch existing users onto new LDT. */ |
375 | pmap_ldt_sync(pmap); |
376 | |
377 | /* Free existing LDT (if any). */ |
378 | if (old_ldt != NULL) { |
379 | ldt_free(old_sel); |
380 | /* exit the mutex before free */ |
381 | mutex_exit(&cpu_lock); |
382 | uvm_km_free(kernel_map, (vaddr_t)old_ldt, old_len, |
383 | UVM_KMF_WIRED); |
384 | } else { |
385 | mutex_exit(&cpu_lock); |
386 | } |
387 | |
388 | return error; |
389 | #endif |
390 | } |
391 | |
392 | int |
393 | x86_iopl(struct lwp *l, void *args, register_t *retval) |
394 | { |
395 | int error; |
396 | struct x86_iopl_args ua; |
397 | #ifdef XEN |
398 | int iopl; |
399 | #else |
400 | struct trapframe *tf = l->l_md.md_regs; |
401 | #endif |
402 | |
403 | error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPL, |
404 | NULL, NULL, NULL, NULL); |
405 | if (error) |
406 | return (error); |
407 | |
408 | if ((error = copyin(args, &ua, sizeof(ua))) != 0) |
409 | return error; |
410 | |
411 | #ifdef XEN |
412 | if (ua.iopl) |
413 | iopl = SEL_UPL; |
414 | else |
415 | iopl = SEL_KPL; |
416 | |
417 | { |
418 | struct physdev_op physop; |
419 | struct pcb *pcb; |
420 | |
421 | pcb = lwp_getpcb(l); |
422 | pcb->pcb_iopl = iopl; |
423 | |
424 | /* Force the change at ring 0. */ |
425 | physop.cmd = PHYSDEVOP_SET_IOPL; |
426 | physop.u.set_iopl.iopl = iopl; |
427 | HYPERVISOR_physdev_op(&physop); |
428 | } |
429 | #elif defined(__x86_64__) |
430 | if (ua.iopl) |
431 | tf->tf_rflags |= PSL_IOPL; |
432 | else |
433 | tf->tf_rflags &= ~PSL_IOPL; |
434 | #else |
435 | if (ua.iopl) |
436 | tf->tf_eflags |= PSL_IOPL; |
437 | else |
438 | tf->tf_eflags &= ~PSL_IOPL; |
439 | #endif |
440 | |
441 | return 0; |
442 | } |
443 | |
444 | int |
445 | x86_get_ioperm(struct lwp *l, void *args, register_t *retval) |
446 | { |
447 | #ifdef IOPERM |
448 | int error; |
449 | struct pcb *pcb = lwp_getpcb(l); |
450 | struct x86_get_ioperm_args ua; |
451 | void *dummymap = NULL; |
452 | void *iomap; |
453 | |
454 | error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPERM_GET, |
455 | NULL, NULL, NULL, NULL); |
456 | if (error) |
457 | return (error); |
458 | |
459 | if ((error = copyin(args, &ua, sizeof(ua))) != 0) |
460 | return (error); |
461 | |
462 | iomap = pcb->pcb_iomap; |
463 | if (iomap == NULL) { |
464 | iomap = dummymap = kmem_alloc(IOMAPSIZE, KM_SLEEP); |
465 | memset(dummymap, 0xff, IOMAPSIZE); |
466 | } |
467 | error = copyout(iomap, ua.iomap, IOMAPSIZE); |
468 | if (dummymap != NULL) { |
469 | kmem_free(dummymap, IOMAPSIZE); |
470 | } |
471 | return error; |
472 | #else |
473 | return EINVAL; |
474 | #endif |
475 | } |
476 | |
477 | int |
478 | x86_set_ioperm(struct lwp *l, void *args, register_t *retval) |
479 | { |
480 | #ifdef IOPERM |
481 | struct cpu_info *ci; |
482 | int error; |
483 | struct pcb *pcb = lwp_getpcb(l); |
484 | struct x86_set_ioperm_args ua; |
485 | void *new; |
486 | void *old; |
487 | |
488 | error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPERM_SET, |
489 | NULL, NULL, NULL, NULL); |
490 | if (error) |
491 | return (error); |
492 | |
493 | if ((error = copyin(args, &ua, sizeof(ua))) != 0) |
494 | return (error); |
495 | |
496 | new = kmem_alloc(IOMAPSIZE, KM_SLEEP); |
497 | error = copyin(ua.iomap, new, IOMAPSIZE); |
498 | if (error) { |
499 | kmem_free(new, IOMAPSIZE); |
500 | return error; |
501 | } |
502 | old = pcb->pcb_iomap; |
503 | pcb->pcb_iomap = new; |
504 | if (old != NULL) { |
505 | kmem_free(old, IOMAPSIZE); |
506 | } |
507 | |
508 | kpreempt_disable(); |
509 | ci = curcpu(); |
510 | memcpy(ci->ci_iomap, pcb->pcb_iomap, sizeof(ci->ci_iomap)); |
511 | ci->ci_tss.tss_iobase = |
512 | ((uintptr_t)ci->ci_iomap - (uintptr_t)&ci->ci_tss) << 16; |
513 | kpreempt_enable(); |
514 | |
515 | return error; |
516 | #else |
517 | return EINVAL; |
518 | #endif |
519 | } |
520 | |
521 | int |
522 | x86_get_mtrr(struct lwp *l, void *args, register_t *retval) |
523 | { |
524 | #ifdef MTRR |
525 | struct x86_get_mtrr_args ua; |
526 | int error, n; |
527 | |
528 | if (mtrr_funcs == NULL) |
529 | return ENOSYS; |
530 | |
531 | error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_MTRR_GET, |
532 | NULL, NULL, NULL, NULL); |
533 | if (error) |
534 | return (error); |
535 | |
536 | error = copyin(args, &ua, sizeof ua); |
537 | if (error != 0) |
538 | return error; |
539 | |
540 | error = copyin(ua.n, &n, sizeof n); |
541 | if (error != 0) |
542 | return error; |
543 | |
544 | KERNEL_LOCK(1, NULL); |
545 | error = mtrr_get(ua.mtrrp, &n, l->l_proc, MTRR_GETSET_USER); |
546 | KERNEL_UNLOCK_ONE(NULL); |
547 | |
548 | copyout(&n, ua.n, sizeof (int)); |
549 | |
550 | return error; |
551 | #else |
552 | return EINVAL; |
553 | #endif |
554 | } |
555 | |
556 | int |
557 | x86_set_mtrr(struct lwp *l, void *args, register_t *retval) |
558 | { |
559 | #ifdef MTRR |
560 | int error, n; |
561 | struct x86_set_mtrr_args ua; |
562 | |
563 | if (mtrr_funcs == NULL) |
564 | return ENOSYS; |
565 | |
566 | error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_MTRR_SET, |
567 | NULL, NULL, NULL, NULL); |
568 | if (error) |
569 | return (error); |
570 | |
571 | error = copyin(args, &ua, sizeof ua); |
572 | if (error != 0) |
573 | return error; |
574 | |
575 | error = copyin(ua.n, &n, sizeof n); |
576 | if (error != 0) |
577 | return error; |
578 | |
579 | KERNEL_LOCK(1, NULL); |
580 | error = mtrr_set(ua.mtrrp, &n, l->l_proc, MTRR_GETSET_USER); |
581 | if (n != 0) |
582 | mtrr_commit(); |
583 | KERNEL_UNLOCK_ONE(NULL); |
584 | |
585 | copyout(&n, ua.n, sizeof n); |
586 | |
587 | return error; |
588 | #else |
589 | return EINVAL; |
590 | #endif |
591 | } |
592 | |
593 | #ifdef __x86_64__ |
594 | #define pcb_fsd pcb_fs |
595 | #define pcb_gsd pcb_gs |
596 | #define segment_descriptor mem_segment_descriptor |
597 | #endif |
598 | |
599 | int |
600 | x86_set_sdbase32(void *arg, char which, lwp_t *l, bool direct) |
601 | { |
602 | struct trapframe *tf = l->l_md.md_regs; |
603 | union descriptor usd; |
604 | struct pcb *pcb; |
605 | uint32_t base; |
606 | int error; |
607 | |
608 | if (direct) { |
609 | base = (vaddr_t)arg; |
610 | } else { |
611 | error = copyin(arg, &base, sizeof(base)); |
612 | if (error != 0) |
613 | return error; |
614 | } |
615 | |
616 | memset(&usd, 0, sizeof(usd)); |
617 | usd.sd.sd_lobase = base & 0xffffff; |
618 | usd.sd.sd_hibase = (base >> 24) & 0xff; |
619 | usd.sd.sd_lolimit = 0xffff; |
620 | usd.sd.sd_hilimit = 0xf; |
621 | usd.sd.sd_type = SDT_MEMRWA; |
622 | usd.sd.sd_dpl = SEL_UPL; |
623 | usd.sd.sd_p = 1; |
624 | usd.sd.sd_def32 = 1; |
625 | usd.sd.sd_gran = 1; |
626 | |
627 | pcb = lwp_getpcb(l); |
628 | kpreempt_disable(); |
629 | if (which == 'f') { |
630 | memcpy(&pcb->pcb_fsd, &usd.sd, |
631 | sizeof(struct segment_descriptor)); |
632 | if (l == curlwp) { |
633 | update_descriptor(&curcpu()->ci_gdt[GUFS_SEL], &usd); |
634 | #ifdef __x86_64__ |
635 | setfs(GSEL(GUFS_SEL, SEL_UPL)); |
636 | #endif |
637 | } |
638 | tf->tf_fs = GSEL(GUFS_SEL, SEL_UPL); |
639 | } else /* which == 'g' */ { |
640 | memcpy(&pcb->pcb_gsd, &usd.sd, |
641 | sizeof(struct segment_descriptor)); |
642 | if (l == curlwp) { |
643 | update_descriptor(&curcpu()->ci_gdt[GUGS_SEL], &usd); |
644 | #ifdef __x86_64__ |
645 | #ifndef XEN |
646 | setusergs(GSEL(GUGS_SEL, SEL_UPL)); |
647 | #else |
648 | HYPERVISOR_set_segment_base(SEGBASE_GS_USER_SEL, |
649 | GSEL(GUGS_SEL, SEL_UPL)); |
650 | #endif |
651 | #endif |
652 | } |
653 | tf->tf_gs = GSEL(GUGS_SEL, SEL_UPL); |
654 | } |
655 | kpreempt_enable(); |
656 | return 0; |
657 | } |
658 | |
659 | int |
660 | x86_set_sdbase(void *arg, char which, lwp_t *l, bool direct) |
661 | { |
662 | #ifdef i386 |
663 | return x86_set_sdbase32(arg, which, l, direct); |
664 | #else |
665 | struct pcb *pcb; |
666 | vaddr_t base; |
667 | |
668 | if (l->l_proc->p_flag & PK_32) { |
669 | return x86_set_sdbase32(arg, which, l, direct); |
670 | } |
671 | |
672 | if (direct) { |
673 | base = (vaddr_t)arg; |
674 | } else { |
675 | int error = copyin(arg, &base, sizeof(base)); |
676 | if (error != 0) |
677 | return error; |
678 | } |
679 | |
680 | if (base >= VM_MAXUSER_ADDRESS) |
681 | return EINVAL; |
682 | |
683 | pcb = lwp_getpcb(l); |
684 | |
685 | kpreempt_disable(); |
686 | switch(which) { |
687 | case 'f': |
688 | pcb->pcb_fs = base; |
689 | if (l == curlwp) |
690 | wrmsr(MSR_FSBASE, pcb->pcb_fs); |
691 | break; |
692 | case 'g': |
693 | pcb->pcb_gs = base; |
694 | if (l == curlwp) |
695 | wrmsr(MSR_KERNELGSBASE, pcb->pcb_gs); |
696 | break; |
697 | default: |
698 | panic("x86_set_sdbase" ); |
699 | } |
700 | kpreempt_enable(); |
701 | |
702 | return 0; |
703 | #endif |
704 | } |
705 | |
706 | int |
707 | x86_get_sdbase32(void *arg, char which) |
708 | { |
709 | struct segment_descriptor *sd; |
710 | uint32_t base; |
711 | |
712 | switch (which) { |
713 | case 'f': |
714 | sd = (void *)&curpcb->pcb_fsd; |
715 | break; |
716 | case 'g': |
717 | sd = (void *)&curpcb->pcb_gsd; |
718 | break; |
719 | default: |
720 | panic("x86_get_sdbase32" ); |
721 | } |
722 | |
723 | base = sd->sd_hibase << 24 | sd->sd_lobase; |
724 | return copyout(&base, arg, sizeof(base)); |
725 | } |
726 | |
727 | int |
728 | x86_get_sdbase(void *arg, char which) |
729 | { |
730 | #ifdef i386 |
731 | return x86_get_sdbase32(arg, which); |
732 | #else |
733 | vaddr_t base; |
734 | struct pcb *pcb; |
735 | |
736 | if (curproc->p_flag & PK_32) { |
737 | return x86_get_sdbase32(arg, which); |
738 | } |
739 | |
740 | pcb = lwp_getpcb(curlwp); |
741 | |
742 | switch(which) { |
743 | case 'f': |
744 | base = pcb->pcb_fs; |
745 | break; |
746 | case 'g': |
747 | base = pcb->pcb_gs; |
748 | break; |
749 | default: |
750 | panic("x86_get_sdbase" ); |
751 | } |
752 | |
753 | return copyout(&base, arg, sizeof(base)); |
754 | #endif |
755 | } |
756 | |
757 | int |
758 | sys_sysarch(struct lwp *l, const struct sys_sysarch_args *uap, register_t *retval) |
759 | { |
760 | /* { |
761 | syscallarg(int) op; |
762 | syscallarg(void *) parms; |
763 | } */ |
764 | int error = 0; |
765 | |
766 | switch(SCARG(uap, op)) { |
767 | case X86_IOPL: |
768 | error = x86_iopl(l, SCARG(uap, parms), retval); |
769 | break; |
770 | |
771 | case X86_GET_LDT: |
772 | error = x86_get_ldt(l, SCARG(uap, parms), retval); |
773 | break; |
774 | |
775 | case X86_SET_LDT: |
776 | error = x86_set_ldt(l, SCARG(uap, parms), retval); |
777 | break; |
778 | |
779 | case X86_GET_IOPERM: |
780 | error = x86_get_ioperm(l, SCARG(uap, parms), retval); |
781 | break; |
782 | |
783 | case X86_SET_IOPERM: |
784 | error = x86_set_ioperm(l, SCARG(uap, parms), retval); |
785 | break; |
786 | |
787 | case X86_GET_MTRR: |
788 | error = x86_get_mtrr(l, SCARG(uap, parms), retval); |
789 | break; |
790 | case X86_SET_MTRR: |
791 | error = x86_set_mtrr(l, SCARG(uap, parms), retval); |
792 | break; |
793 | |
794 | #ifdef VM86 |
795 | case X86_VM86: |
796 | error = x86_vm86(l, SCARG(uap, parms), retval); |
797 | break; |
798 | case X86_OLD_VM86: |
799 | error = compat_16_x86_vm86(l, SCARG(uap, parms), retval); |
800 | break; |
801 | #endif |
802 | |
803 | #ifdef PERFCTRS |
804 | case X86_PMC_INFO: |
805 | KERNEL_LOCK(1, NULL); |
806 | error = pmc_info(l, SCARG(uap, parms), retval); |
807 | KERNEL_UNLOCK_ONE(NULL); |
808 | break; |
809 | |
810 | case X86_PMC_STARTSTOP: |
811 | KERNEL_LOCK(1, NULL); |
812 | error = pmc_startstop(l, SCARG(uap, parms), retval); |
813 | KERNEL_UNLOCK_ONE(NULL); |
814 | break; |
815 | |
816 | case X86_PMC_READ: |
817 | KERNEL_LOCK(1, NULL); |
818 | error = pmc_read(l, SCARG(uap, parms), retval); |
819 | KERNEL_UNLOCK_ONE(NULL); |
820 | break; |
821 | #endif |
822 | |
823 | case X86_SET_FSBASE: |
824 | error = x86_set_sdbase(SCARG(uap, parms), 'f', curlwp, false); |
825 | break; |
826 | |
827 | case X86_SET_GSBASE: |
828 | error = x86_set_sdbase(SCARG(uap, parms), 'g', curlwp, false); |
829 | break; |
830 | |
831 | case X86_GET_FSBASE: |
832 | error = x86_get_sdbase(SCARG(uap, parms), 'f'); |
833 | break; |
834 | |
835 | case X86_GET_GSBASE: |
836 | error = x86_get_sdbase(SCARG(uap, parms), 'g'); |
837 | break; |
838 | |
839 | default: |
840 | error = EINVAL; |
841 | break; |
842 | } |
843 | return (error); |
844 | } |
845 | |
846 | int |
847 | cpu_lwp_setprivate(lwp_t *l, void *addr) |
848 | { |
849 | |
850 | #ifdef __x86_64__ |
851 | if ((l->l_proc->p_flag & PK_32) == 0) { |
852 | return x86_set_sdbase(addr, 'f', l, true); |
853 | } |
854 | #endif |
855 | return x86_set_sdbase(addr, 'g', l, true); |
856 | } |
857 | |