Home | History | Annotate | Line # | Download | only in x86
      1 /*	$NetBSD: sys_machdep.c,v 1.58 2022/08/20 23:49:31 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1998, 2007, 2009, 2017 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, by Andrew Doran, and by Maxime Villard.
      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.58 2022/08/20 23:49:31 riastradh Exp $");
     34 
     35 #include "opt_mtrr.h"
     36 #include "opt_user_ldt.h"
     37 #include "opt_compat_netbsd.h"
     38 #include "opt_xen.h"
     39 
     40 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/ioctl.h>
     43 #include <sys/file.h>
     44 #include <sys/time.h>
     45 #include <sys/proc.h>
     46 #include <sys/uio.h>
     47 #include <sys/kernel.h>
     48 #include <sys/buf.h>
     49 #include <sys/signal.h>
     50 #include <sys/malloc.h>
     51 #include <sys/kmem.h>
     52 #include <sys/kauth.h>
     53 #include <sys/cpu.h>
     54 #include <sys/mount.h>
     55 #include <sys/syscallargs.h>
     56 
     57 #include <uvm/uvm_extern.h>
     58 
     59 #include <machine/cpufunc.h>
     60 #include <machine/gdt.h>
     61 #include <machine/psl.h>
     62 #include <machine/reg.h>
     63 #include <machine/sysarch.h>
     64 #include <machine/mtrr.h>
     65 #include <machine/pmap_private.h>
     66 
     67 #if defined(__x86_64__) || defined(XENPV)
     68 #undef	IOPERM	/* not implemented */
     69 #else
     70 #define	IOPERM
     71 #endif
     72 
     73 #if defined(XENPV) && defined(USER_LDT)
     74 #error "USER_LDT not supported on XENPV"
     75 #endif
     76 
     77 extern struct vm_map *kernel_map;
     78 
     79 static int x86_get_ioperm(struct lwp *, void *, register_t *);
     80 static int x86_set_ioperm(struct lwp *, void *, register_t *);
     81 static int x86_set_sdbase32(void *, char, lwp_t *, bool);
     82 int x86_set_sdbase(void *, char, lwp_t *, bool);
     83 static int x86_get_sdbase32(void *, char);
     84 int x86_get_sdbase(void *, char);
     85 
     86 #ifdef i386
     87 static int
     88 x86_get_ldt(struct lwp *l, void *args, register_t *retval)
     89 {
     90 #ifndef USER_LDT
     91 	return EINVAL;
     92 #else
     93 	struct x86_get_ldt_args ua;
     94 	union descriptor *cp;
     95 	int error;
     96 
     97 	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
     98 		return error;
     99 
    100 	if (ua.num < 0 || ua.num > MAX_USERLDT_SLOTS)
    101 		return EINVAL;
    102 
    103 	cp = malloc(ua.num * sizeof(union descriptor), M_TEMP, M_WAITOK);
    104 	if (cp == NULL)
    105 		return ENOMEM;
    106 
    107 	error = x86_get_ldt1(l, &ua, cp);
    108 	*retval = ua.num;
    109 	if (error == 0)
    110 		error = copyout(cp, ua.desc, ua.num * sizeof(*cp));
    111 
    112 	free(cp, M_TEMP);
    113 	return error;
    114 #endif
    115 }
    116 #endif
    117 
    118 int
    119 x86_get_ldt1(struct lwp *l, struct x86_get_ldt_args *ua, union descriptor *cp)
    120 {
    121 #ifndef USER_LDT
    122 	return EINVAL;
    123 #else
    124 	int error;
    125 	struct proc *p = l->l_proc;
    126 	pmap_t pmap = p->p_vmspace->vm_map.pmap;
    127 	int nldt, num;
    128 	union descriptor *lp;
    129 
    130 #ifdef __x86_64__
    131 	const size_t min_ldt_size = LDT_SIZE;
    132 #else
    133 	const size_t min_ldt_size = NLDT * sizeof(union descriptor);
    134 #endif
    135 
    136 	error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_LDT_GET,
    137 	    NULL, NULL, NULL, NULL);
    138 	if (error)
    139 		return error;
    140 
    141 	if (ua->start < 0 || ua->num < 0 ||
    142 	    ua->start > MAX_USERLDT_SLOTS || ua->num > MAX_USERLDT_SLOTS ||
    143 	    ua->start + ua->num > MAX_USERLDT_SLOTS)
    144 		return EINVAL;
    145 
    146 	if (ua->start * sizeof(union descriptor) < min_ldt_size)
    147 		return EINVAL;
    148 
    149 	mutex_enter(&cpu_lock);
    150 
    151 	if (pmap->pm_ldt != NULL) {
    152 		nldt = MAX_USERLDT_SIZE / sizeof(*lp);
    153 		lp = pmap->pm_ldt;
    154 	} else {
    155 #ifdef __x86_64__
    156 		nldt = LDT_SIZE / sizeof(*lp);
    157 #else
    158 		nldt = NLDT;
    159 #endif
    160 		lp = (union descriptor *)ldtstore;
    161 	}
    162 
    163 	if (ua->start > nldt) {
    164 		mutex_exit(&cpu_lock);
    165 		return EINVAL;
    166 	}
    167 
    168 	lp += ua->start;
    169 	num = uimin(ua->num, nldt - ua->start);
    170 	ua->num = num;
    171 
    172 	memcpy(cp, lp, num * sizeof(union descriptor));
    173 	mutex_exit(&cpu_lock);
    174 
    175 	return 0;
    176 #endif
    177 }
    178 
    179 #ifdef i386
    180 static int
    181 x86_set_ldt(struct lwp *l, void *args, register_t *retval)
    182 {
    183 #ifndef USER_LDT
    184 	return EINVAL;
    185 #else
    186 	struct x86_set_ldt_args ua;
    187 	union descriptor *descv;
    188 	int error;
    189 
    190 	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
    191 		return error;
    192 
    193 	if (ua.num < 0 || ua.num > MAX_USERLDT_SLOTS)
    194 		return EINVAL;
    195 
    196 	descv = malloc(sizeof (*descv) * ua.num, M_TEMP, M_WAITOK);
    197 	error = copyin(ua.desc, descv, sizeof (*descv) * ua.num);
    198 	if (error == 0)
    199 		error = x86_set_ldt1(l, &ua, descv);
    200 	*retval = ua.start;
    201 
    202 	free(descv, M_TEMP);
    203 	return error;
    204 #endif
    205 }
    206 #endif
    207 
    208 int
    209 x86_set_ldt1(struct lwp *l, struct x86_set_ldt_args *ua,
    210     union descriptor *descv)
    211 {
    212 #ifndef USER_LDT
    213 	return EINVAL;
    214 #else
    215 	int error, i, n, old_sel, new_sel;
    216 	struct proc *p = l->l_proc;
    217 	pmap_t pmap = p->p_vmspace->vm_map.pmap;
    218 	union descriptor *old_ldt, *new_ldt;
    219 
    220 #ifdef __x86_64__
    221 	const size_t min_ldt_size = LDT_SIZE;
    222 #else
    223 	const size_t min_ldt_size = NLDT * sizeof(union descriptor);
    224 #endif
    225 
    226 	error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_LDT_SET,
    227 	    NULL, NULL, NULL, NULL);
    228 	if (error)
    229 		return error;
    230 
    231 	if (ua->start < 0 || ua->num < 0 ||
    232 	    ua->start > MAX_USERLDT_SLOTS || ua->num > MAX_USERLDT_SLOTS ||
    233 	    ua->start + ua->num > MAX_USERLDT_SLOTS)
    234 		return EINVAL;
    235 
    236 	if (ua->start * sizeof(union descriptor) < min_ldt_size)
    237 		return EINVAL;
    238 
    239 	/* Check descriptors for access violations. */
    240 	for (i = 0; i < ua->num; i++) {
    241 		union descriptor *desc = &descv[i];
    242 
    243 #ifdef __x86_64__
    244 		if (desc->sd.sd_long != 0)
    245 			return EACCES;
    246 #endif
    247 
    248 		switch (desc->sd.sd_type) {
    249 		case SDT_SYSNULL:
    250 			desc->sd.sd_p = 0;
    251 			break;
    252 		case SDT_MEMEC:
    253 		case SDT_MEMEAC:
    254 		case SDT_MEMERC:
    255 		case SDT_MEMERAC:
    256 			/* Must be "present" if executable and conforming. */
    257 			if (desc->sd.sd_p == 0)
    258 				return EACCES;
    259 			break;
    260 		case SDT_MEMRO:
    261 		case SDT_MEMROA:
    262 		case SDT_MEMRW:
    263 		case SDT_MEMRWA:
    264 		case SDT_MEMROD:
    265 		case SDT_MEMRODA:
    266 		case SDT_MEMRWD:
    267 		case SDT_MEMRWDA:
    268 		case SDT_MEME:
    269 		case SDT_MEMEA:
    270 		case SDT_MEMER:
    271 		case SDT_MEMERA:
    272 			break;
    273 		default:
    274 			return EACCES;
    275 		}
    276 
    277 		if (desc->sd.sd_p != 0) {
    278 			/* Only user (ring-3) descriptors may be present. */
    279 			if (desc->sd.sd_dpl != SEL_UPL)
    280 				return EACCES;
    281 		}
    282 	}
    283 
    284 	/*
    285 	 * Install selected changes.
    286 	 */
    287 
    288 	/* Allocate a new LDT. */
    289 	new_ldt = (union descriptor *)uvm_km_alloc(kernel_map,
    290 	    MAX_USERLDT_SIZE, 0, UVM_KMF_WIRED | UVM_KMF_ZERO | UVM_KMF_WAITVA);
    291 
    292 	mutex_enter(&cpu_lock);
    293 
    294 	/* Copy existing entries, if any. */
    295 	if (pmap->pm_ldt != NULL) {
    296 		old_ldt = pmap->pm_ldt;
    297 		old_sel = pmap->pm_ldt_sel;
    298 		memcpy(new_ldt, old_ldt, MAX_USERLDT_SIZE);
    299 	} else {
    300 		old_ldt = NULL;
    301 		old_sel = -1;
    302 		memcpy(new_ldt, ldtstore, min_ldt_size);
    303 	}
    304 
    305 	/* Apply requested changes. */
    306 	for (i = 0, n = ua->start; i < ua->num; i++, n++) {
    307 		new_ldt[n] = descv[i];
    308 	}
    309 
    310 	/* Allocate LDT selector. */
    311 	new_sel = ldt_alloc(new_ldt, MAX_USERLDT_SIZE);
    312 	if (new_sel == -1) {
    313 		mutex_exit(&cpu_lock);
    314 		uvm_km_free(kernel_map, (vaddr_t)new_ldt, MAX_USERLDT_SIZE,
    315 		    UVM_KMF_WIRED);
    316 		return ENOMEM;
    317 	}
    318 
    319 	/* All changes are now globally visible.  Swap in the new LDT. */
    320 	atomic_store_relaxed(&pmap->pm_ldt_sel, new_sel);
    321 	/* membar_store_store for pmap_fork() to read these unlocked safely */
    322 	membar_producer();
    323 	atomic_store_relaxed(&pmap->pm_ldt, new_ldt);
    324 
    325 	/* Switch existing users onto new LDT. */
    326 	pmap_ldt_sync(pmap);
    327 
    328 	/* Free existing LDT (if any). */
    329 	if (old_ldt != NULL) {
    330 		ldt_free(old_sel);
    331 		/* exit the mutex before free */
    332 		mutex_exit(&cpu_lock);
    333 		uvm_km_free(kernel_map, (vaddr_t)old_ldt, MAX_USERLDT_SIZE,
    334 		    UVM_KMF_WIRED);
    335 	} else {
    336 		mutex_exit(&cpu_lock);
    337 	}
    338 
    339 	return error;
    340 #endif
    341 }
    342 
    343 int
    344 x86_iopl(struct lwp *l, void *args, register_t *retval)
    345 {
    346 	int error;
    347 	struct x86_iopl_args ua;
    348 #ifdef XENPV
    349 	int iopl;
    350 #else
    351 	struct trapframe *tf = l->l_md.md_regs;
    352 #endif
    353 
    354 	error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPL,
    355 	    NULL, NULL, NULL, NULL);
    356 	if (error)
    357 		return error;
    358 
    359 	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
    360 		return error;
    361 
    362 #ifdef XENPV
    363 	if (ua.iopl)
    364 		iopl = SEL_UPL;
    365 	else
    366 		iopl = SEL_KPL;
    367 
    368     {
    369 	struct pcb *pcb;
    370 
    371 	pcb = lwp_getpcb(l);
    372 	pcb->pcb_iopl = iopl;
    373 
    374 	/* Force the change at ring 0. */
    375 	struct physdev_set_iopl set_iopl;
    376 	set_iopl.iopl = iopl;
    377 	HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
    378     }
    379 #elif defined(__x86_64__)
    380 	if (ua.iopl)
    381 		tf->tf_rflags |= PSL_IOPL;
    382 	else
    383 		tf->tf_rflags &= ~PSL_IOPL;
    384 #else
    385 	if (ua.iopl)
    386 		tf->tf_eflags |= PSL_IOPL;
    387 	else
    388 		tf->tf_eflags &= ~PSL_IOPL;
    389 #endif
    390 
    391 	return 0;
    392 }
    393 
    394 static int
    395 x86_get_ioperm(struct lwp *l, void *args, register_t *retval)
    396 {
    397 #ifdef IOPERM
    398 	int error;
    399 	struct pcb *pcb = lwp_getpcb(l);
    400 	struct x86_get_ioperm_args ua;
    401 	void *dummymap = NULL;
    402 	void *iomap;
    403 
    404 	error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPERM_GET,
    405 	    NULL, NULL, NULL, NULL);
    406 	if (error)
    407 		return error;
    408 
    409 	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
    410 		return error;
    411 
    412 	iomap = pcb->pcb_iomap;
    413 	if (iomap == NULL) {
    414 		iomap = dummymap = kmem_alloc(IOMAPSIZE, KM_SLEEP);
    415 		memset(dummymap, 0xff, IOMAPSIZE);
    416 	}
    417 	error = copyout(iomap, ua.iomap, IOMAPSIZE);
    418 	if (dummymap != NULL) {
    419 		kmem_free(dummymap, IOMAPSIZE);
    420 	}
    421 	return error;
    422 #else
    423 	return EINVAL;
    424 #endif
    425 }
    426 
    427 static int
    428 x86_set_ioperm(struct lwp *l, void *args, register_t *retval)
    429 {
    430 #ifdef IOPERM
    431 	struct cpu_info *ci;
    432 	int error;
    433 	struct pcb *pcb = lwp_getpcb(l);
    434 	struct x86_set_ioperm_args ua;
    435 	void *new;
    436 	void *old;
    437 
    438 	error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_IOPERM_SET,
    439 	    NULL, NULL, NULL, NULL);
    440 	if (error)
    441 		return error;
    442 
    443 	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
    444 		return error;
    445 
    446 	new = kmem_alloc(IOMAPSIZE, KM_SLEEP);
    447 	error = copyin(ua.iomap, new, IOMAPSIZE);
    448 	if (error) {
    449 		kmem_free(new, IOMAPSIZE);
    450 		return error;
    451 	}
    452 	old = pcb->pcb_iomap;
    453 	pcb->pcb_iomap = new;
    454 	if (old != NULL) {
    455 		kmem_free(old, IOMAPSIZE);
    456 	}
    457 
    458 	CTASSERT(offsetof(struct cpu_tss, iomap) -
    459 	    offsetof(struct cpu_tss, tss) == IOMAP_VALIDOFF);
    460 
    461 	kpreempt_disable();
    462 	ci = curcpu();
    463 	memcpy(ci->ci_tss->iomap, pcb->pcb_iomap, IOMAPSIZE);
    464 	ci->ci_tss->tss.tss_iobase = IOMAP_VALIDOFF << 16;
    465 	kpreempt_enable();
    466 
    467 	return error;
    468 #else
    469 	return EINVAL;
    470 #endif
    471 }
    472 
    473 static int
    474 x86_get_mtrr(struct lwp *l, void *args, register_t *retval)
    475 {
    476 #ifdef MTRR
    477 	struct x86_get_mtrr_args ua;
    478 	int error, n;
    479 
    480 	if (mtrr_funcs == NULL)
    481 		return ENOSYS;
    482 
    483 	error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_MTRR_GET,
    484 	    NULL, NULL, NULL, NULL);
    485 	if (error)
    486 		return error;
    487 
    488 	error = copyin(args, &ua, sizeof ua);
    489 	if (error != 0)
    490 		return error;
    491 
    492 	error = copyin(ua.n, &n, sizeof n);
    493 	if (error != 0)
    494 		return error;
    495 
    496 	KERNEL_LOCK(1, NULL);
    497 	error = mtrr_get(ua.mtrrp, &n, l->l_proc, MTRR_GETSET_USER);
    498 	KERNEL_UNLOCK_ONE(NULL);
    499 
    500 	copyout(&n, ua.n, sizeof (int));
    501 
    502 	return error;
    503 #else
    504 	return EINVAL;
    505 #endif
    506 }
    507 
    508 static int
    509 x86_set_mtrr(struct lwp *l, void *args, register_t *retval)
    510 {
    511 #ifdef MTRR
    512 	int error, n;
    513 	struct x86_set_mtrr_args ua;
    514 
    515 	if (mtrr_funcs == NULL)
    516 		return ENOSYS;
    517 
    518 	error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_MTRR_SET,
    519 	    NULL, NULL, NULL, NULL);
    520 	if (error)
    521 		return error;
    522 
    523 	error = copyin(args, &ua, sizeof ua);
    524 	if (error != 0)
    525 		return error;
    526 
    527 	error = copyin(ua.n, &n, sizeof n);
    528 	if (error != 0)
    529 		return error;
    530 
    531 	KERNEL_LOCK(1, NULL);
    532 	error = mtrr_set(ua.mtrrp, &n, l->l_proc, MTRR_GETSET_USER);
    533 	if (n != 0)
    534 		mtrr_commit();
    535 	KERNEL_UNLOCK_ONE(NULL);
    536 
    537 	copyout(&n, ua.n, sizeof n);
    538 
    539 	return error;
    540 #else
    541 	return EINVAL;
    542 #endif
    543 }
    544 
    545 #ifdef __x86_64__
    546 #define pcb_fsd pcb_fs
    547 #define pcb_gsd pcb_gs
    548 #define segment_descriptor mem_segment_descriptor
    549 #endif
    550 
    551 static int
    552 x86_set_sdbase32(void *arg, char which, lwp_t *l, bool direct)
    553 {
    554 	struct trapframe *tf = l->l_md.md_regs;
    555 	union descriptor usd;
    556 	struct pcb *pcb;
    557 	uint32_t base;
    558 	int error;
    559 
    560 	if (direct) {
    561 		base = (vaddr_t)arg;
    562 	} else {
    563 		error = copyin(arg, &base, sizeof(base));
    564 		if (error != 0)
    565 			return error;
    566 	}
    567 
    568 	memset(&usd, 0, sizeof(usd));
    569 	usd.sd.sd_lobase = base & 0xffffff;
    570 	usd.sd.sd_hibase = (base >> 24) & 0xff;
    571 	usd.sd.sd_lolimit = 0xffff;
    572 	usd.sd.sd_hilimit = 0xf;
    573 	usd.sd.sd_type = SDT_MEMRWA;
    574 	usd.sd.sd_dpl = SEL_UPL;
    575 	usd.sd.sd_p = 1;
    576 	usd.sd.sd_def32 = 1;
    577 	usd.sd.sd_gran = 1;
    578 
    579 	pcb = lwp_getpcb(l);
    580 	kpreempt_disable();
    581 	if (which == 'f') {
    582 		memcpy(&pcb->pcb_fsd, &usd.sd,
    583 		    sizeof(struct segment_descriptor));
    584 		if (l == curlwp) {
    585 			update_descriptor(&curcpu()->ci_gdt[GUFS_SEL], &usd);
    586 		}
    587 		tf->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
    588 	} else /* which == 'g' */ {
    589 		memcpy(&pcb->pcb_gsd, &usd.sd,
    590 		    sizeof(struct segment_descriptor));
    591 		if (l == curlwp) {
    592 			update_descriptor(&curcpu()->ci_gdt[GUGS_SEL], &usd);
    593 #if defined(__x86_64__) && defined(XENPV)
    594 			setusergs(GSEL(GUGS_SEL, SEL_UPL));
    595 #endif
    596 		}
    597 		tf->tf_gs = GSEL(GUGS_SEL, SEL_UPL);
    598 	}
    599 	kpreempt_enable();
    600 	return 0;
    601 }
    602 
    603 int
    604 x86_set_sdbase(void *arg, char which, lwp_t *l, bool direct)
    605 {
    606 #ifdef i386
    607 	return x86_set_sdbase32(arg, which, l, direct);
    608 #else
    609 	struct pcb *pcb;
    610 	vaddr_t base;
    611 
    612 	if (l->l_proc->p_flag & PK_32) {
    613 		return x86_set_sdbase32(arg, which, l, direct);
    614 	}
    615 
    616 	if (direct) {
    617 		base = (vaddr_t)arg;
    618 	} else {
    619 		int error = copyin(arg, &base, sizeof(base));
    620 		if (error != 0)
    621 			return error;
    622 	}
    623 
    624 	if (base >= VM_MAXUSER_ADDRESS)
    625 		return EINVAL;
    626 
    627 	pcb = lwp_getpcb(l);
    628 
    629 	kpreempt_disable();
    630 	switch (which) {
    631 	case 'f':
    632 		pcb->pcb_fs = base;
    633 		if (l == curlwp)
    634 			wrmsr(MSR_FSBASE, pcb->pcb_fs);
    635 		break;
    636 	case 'g':
    637 		pcb->pcb_gs = base;
    638 		if (l == curlwp)
    639 			wrmsr(MSR_KERNELGSBASE, pcb->pcb_gs);
    640 		break;
    641 	default:
    642 		panic("x86_set_sdbase");
    643 	}
    644 	kpreempt_enable();
    645 
    646 	return 0;
    647 #endif
    648 }
    649 
    650 static int
    651 x86_get_sdbase32(void *arg, char which)
    652 {
    653 	struct segment_descriptor *sd;
    654 	uint32_t base;
    655 
    656 	switch (which) {
    657 	case 'f':
    658 		sd = (void *)&curpcb->pcb_fsd;
    659 		break;
    660 	case 'g':
    661 		sd = (void *)&curpcb->pcb_gsd;
    662 		break;
    663 	default:
    664 		panic("x86_get_sdbase32");
    665 	}
    666 
    667 	base = sd->sd_hibase << 24 | sd->sd_lobase;
    668 	return copyout(&base, arg, sizeof(base));
    669 }
    670 
    671 int
    672 x86_get_sdbase(void *arg, char which)
    673 {
    674 #ifdef i386
    675 	return x86_get_sdbase32(arg, which);
    676 #else
    677 	vaddr_t base;
    678 	struct pcb *pcb;
    679 
    680 	if (curproc->p_flag & PK_32) {
    681 		return x86_get_sdbase32(arg, which);
    682 	}
    683 
    684 	pcb = lwp_getpcb(curlwp);
    685 
    686 	switch (which) {
    687 	case 'f':
    688 		base = pcb->pcb_fs;
    689 		break;
    690 	case 'g':
    691 		base = pcb->pcb_gs;
    692 		break;
    693 	default:
    694 		panic("x86_get_sdbase");
    695 	}
    696 
    697 	return copyout(&base, arg, sizeof(base));
    698 #endif
    699 }
    700 
    701 int
    702 sys_sysarch(struct lwp *l, const struct sys_sysarch_args *uap,
    703     register_t *retval)
    704 {
    705 	/* {
    706 		syscallarg(int) op;
    707 		syscallarg(void *) parms;
    708 	} */
    709 	int error = 0;
    710 
    711 	switch (SCARG(uap, op)) {
    712 	case X86_IOPL:
    713 		error = x86_iopl(l, SCARG(uap, parms), retval);
    714 		break;
    715 
    716 #ifdef i386
    717 	/*
    718 	 * On amd64, this is done via netbsd32_sysarch.
    719 	 */
    720 	case X86_GET_LDT:
    721 		error = x86_get_ldt(l, SCARG(uap, parms), retval);
    722 		break;
    723 
    724 	case X86_SET_LDT:
    725 		error = x86_set_ldt(l, SCARG(uap, parms), retval);
    726 		break;
    727 #endif
    728 
    729 	case X86_GET_IOPERM:
    730 		error = x86_get_ioperm(l, SCARG(uap, parms), retval);
    731 		break;
    732 
    733 	case X86_SET_IOPERM:
    734 		error = x86_set_ioperm(l, SCARG(uap, parms), retval);
    735 		break;
    736 
    737 	case X86_GET_MTRR:
    738 		error = x86_get_mtrr(l, SCARG(uap, parms), retval);
    739 		break;
    740 	case X86_SET_MTRR:
    741 		error = x86_set_mtrr(l, SCARG(uap, parms), retval);
    742 		break;
    743 
    744 	case X86_SET_FSBASE:
    745 		error = x86_set_sdbase(SCARG(uap, parms), 'f', curlwp, false);
    746 		break;
    747 
    748 	case X86_SET_GSBASE:
    749 		error = x86_set_sdbase(SCARG(uap, parms), 'g', curlwp, false);
    750 		break;
    751 
    752 	case X86_GET_FSBASE:
    753 		error = x86_get_sdbase(SCARG(uap, parms), 'f');
    754 		break;
    755 
    756 	case X86_GET_GSBASE:
    757 		error = x86_get_sdbase(SCARG(uap, parms), 'g');
    758 		break;
    759 
    760 	default:
    761 		error = EINVAL;
    762 		break;
    763 	}
    764 	return error;
    765 }
    766 
    767 int
    768 cpu_lwp_setprivate(lwp_t *l, void *addr)
    769 {
    770 
    771 #ifdef __x86_64__
    772 	if ((l->l_proc->p_flag & PK_32) == 0) {
    773 		return x86_set_sdbase(addr, 'f', l, true);
    774 	}
    775 #endif
    776 	return x86_set_sdbase(addr, 'g', l, true);
    777 }
    778