xref: /onnv-gate/usr/src/uts/intel/ia32/syscall/lwp_private.c (revision 5084:7d838c5c0eed)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53446Smrj  * Common Development and Distribution License (the "License").
63446Smrj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223446Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/disp.h>
310Sstevel@tonic-gate #include <sys/sysmacros.h>
320Sstevel@tonic-gate #include <sys/cpuvar.h>
330Sstevel@tonic-gate #include <sys/systm.h>
340Sstevel@tonic-gate #include <sys/thread.h>
350Sstevel@tonic-gate #include <sys/lwp.h>
360Sstevel@tonic-gate #include <sys/segments.h>
370Sstevel@tonic-gate #include <sys/privregs.h>
380Sstevel@tonic-gate #include <sys/cmn_err.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate int
lwp_setprivate(klwp_t * lwp,int which,uintptr_t base)410Sstevel@tonic-gate lwp_setprivate(klwp_t *lwp, int which, uintptr_t base)
420Sstevel@tonic-gate {
430Sstevel@tonic-gate 	pcb_t *pcb = &lwp->lwp_pcb;
440Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
450Sstevel@tonic-gate 	kthread_t *t = lwptot(lwp);
460Sstevel@tonic-gate 	int thisthread = t == curthread;
470Sstevel@tonic-gate 	int rval;
480Sstevel@tonic-gate 
490Sstevel@tonic-gate 	if (thisthread)
500Sstevel@tonic-gate 		kpreempt_disable();
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #if defined(__amd64)
530Sstevel@tonic-gate 
540Sstevel@tonic-gate 	/*
550Sstevel@tonic-gate 	 * 32-bit compatibility processes point to the per-cpu GDT segment
560Sstevel@tonic-gate 	 * descriptors that are virtualized to the lwp.  That allows 32-bit
570Sstevel@tonic-gate 	 * programs to mess with %fs and %gs; in particular it allows
580Sstevel@tonic-gate 	 * things like this:
590Sstevel@tonic-gate 	 *
600Sstevel@tonic-gate 	 *	movw	%gs, %ax
610Sstevel@tonic-gate 	 *	...
620Sstevel@tonic-gate 	 *	movw	%ax, %gs
630Sstevel@tonic-gate 	 *
640Sstevel@tonic-gate 	 * to work, which is needed by emulators for legacy application
650Sstevel@tonic-gate 	 * environments ..
660Sstevel@tonic-gate 	 *
673446Smrj 	 * 64-bit processes may also point to a per-cpu GDT segment descriptor
680Sstevel@tonic-gate 	 * virtualized to the lwp.  However the descriptor base is forced
690Sstevel@tonic-gate 	 * to zero (because we can't express the full 64-bit address range
700Sstevel@tonic-gate 	 * in a long mode descriptor), so don't reload segment registers
713446Smrj 	 * in a 64-bit program! 64-bit processes must have selector values
723446Smrj 	 * of zero for %fs and %gs to use the 64-bit fs_base and gs_base
733446Smrj 	 * respectively.
740Sstevel@tonic-gate 	 */
754503Ssudheer 	if (pcb->pcb_rupdate == 0) {
760Sstevel@tonic-gate 		pcb->pcb_ds = rp->r_ds;
770Sstevel@tonic-gate 		pcb->pcb_es = rp->r_es;
780Sstevel@tonic-gate 		pcb->pcb_fs = rp->r_fs;
790Sstevel@tonic-gate 		pcb->pcb_gs = rp->r_gs;
804503Ssudheer 		pcb->pcb_rupdate = 1;
810Sstevel@tonic-gate 		t->t_post_sys = 1;
820Sstevel@tonic-gate 	}
830Sstevel@tonic-gate 	ASSERT(t->t_post_sys);
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	switch (which) {
860Sstevel@tonic-gate 	case _LWP_FSBASE:
873446Smrj 		if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
880Sstevel@tonic-gate 			set_usegd(&pcb->pcb_fsdesc, SDP_LONG, 0, 0,
890Sstevel@tonic-gate 			    SDT_MEMRWA, SEL_UPL, SDP_BYTES, SDP_OP32);
903446Smrj 			rval = pcb->pcb_fs = 0;	/* null gdt descriptor */
913446Smrj 		} else {
920Sstevel@tonic-gate 			set_usegd(&pcb->pcb_fsdesc, SDP_SHORT, (void *)base, -1,
930Sstevel@tonic-gate 			    SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
943446Smrj 			rval = pcb->pcb_fs = LWPFS_SEL;
953446Smrj 		}
960Sstevel@tonic-gate 		if (thisthread)
97*5084Sjohnlev 			gdt_update_usegd(GDT_LWPFS, &pcb->pcb_fsdesc);
98*5084Sjohnlev 
990Sstevel@tonic-gate 		pcb->pcb_fsbase = base;
1000Sstevel@tonic-gate 		break;
1010Sstevel@tonic-gate 	case _LWP_GSBASE:
1023446Smrj 		if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
1030Sstevel@tonic-gate 			set_usegd(&pcb->pcb_gsdesc, SDP_LONG, 0, 0,
1040Sstevel@tonic-gate 			    SDT_MEMRWA, SEL_UPL, SDP_BYTES, SDP_OP32);
1053446Smrj 			rval = pcb->pcb_gs = 0;	/* null gdt descriptor */
1063446Smrj 		} else {
1070Sstevel@tonic-gate 			set_usegd(&pcb->pcb_gsdesc, SDP_SHORT, (void *)base, -1,
1080Sstevel@tonic-gate 			    SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
1093446Smrj 			rval = pcb->pcb_gs = LWPGS_SEL;
1103446Smrj 		}
1110Sstevel@tonic-gate 		if (thisthread)
112*5084Sjohnlev 			gdt_update_usegd(GDT_LWPGS, &pcb->pcb_gsdesc);
113*5084Sjohnlev 
1140Sstevel@tonic-gate 		pcb->pcb_gsbase = base;
1150Sstevel@tonic-gate 		break;
1160Sstevel@tonic-gate 	default:
1170Sstevel@tonic-gate 		rval = -1;
1180Sstevel@tonic-gate 		break;
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate #elif defined(__i386)
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	/*
1243446Smrj 	 * 32-bit processes point to the per-cpu GDT segment
1250Sstevel@tonic-gate 	 * descriptors that are virtualized to the lwp.
1260Sstevel@tonic-gate 	 */
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	switch	(which) {
1290Sstevel@tonic-gate 	case _LWP_FSBASE:
1300Sstevel@tonic-gate 		set_usegd(&pcb->pcb_fsdesc, (void *)base, -1,
1310Sstevel@tonic-gate 		    SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
1320Sstevel@tonic-gate 		if (thisthread)
133*5084Sjohnlev 			gdt_update_usegd(GDT_LWPFS, &pcb->pcb_fsdesc);
134*5084Sjohnlev 
1350Sstevel@tonic-gate 		rval = rp->r_fs = LWPFS_SEL;
1360Sstevel@tonic-gate 		break;
1370Sstevel@tonic-gate 	case _LWP_GSBASE:
1380Sstevel@tonic-gate 		set_usegd(&pcb->pcb_gsdesc, (void *)base, -1,
1390Sstevel@tonic-gate 		    SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
1400Sstevel@tonic-gate 		if (thisthread)
141*5084Sjohnlev 			gdt_update_usegd(GDT_LWPGS, &pcb->pcb_gsdesc);
142*5084Sjohnlev 
1430Sstevel@tonic-gate 		rval = rp->r_gs = LWPGS_SEL;
1440Sstevel@tonic-gate 		break;
1450Sstevel@tonic-gate 	default:
1460Sstevel@tonic-gate 		rval = -1;
1470Sstevel@tonic-gate 		break;
1480Sstevel@tonic-gate 	}
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate #endif	/* __i386 */
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	if (thisthread)
1530Sstevel@tonic-gate 		kpreempt_enable();
1540Sstevel@tonic-gate 	return (rval);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate static int
lwp_getprivate(klwp_t * lwp,int which,uintptr_t base)1580Sstevel@tonic-gate lwp_getprivate(klwp_t *lwp, int which, uintptr_t base)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	pcb_t *pcb = &lwp->lwp_pcb;
1610Sstevel@tonic-gate 	struct regs *rp = lwptoregs(lwp);
1620Sstevel@tonic-gate 	uintptr_t sbase;
1630Sstevel@tonic-gate 	int error = 0;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	ASSERT(lwptot(lwp) == curthread);
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	kpreempt_disable();
1680Sstevel@tonic-gate 	switch (which) {
1690Sstevel@tonic-gate #if defined(__amd64)
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	case _LWP_FSBASE:
1720Sstevel@tonic-gate 		if ((sbase = pcb->pcb_fsbase) != 0) {
1733446Smrj 			if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
1744503Ssudheer 				if (pcb->pcb_rupdate == 1) {
1753446Smrj 					if (pcb->pcb_fs == 0)
1763446Smrj 						break;
1773446Smrj 				} else {
1783446Smrj 					if (rp->r_fs == 0)
1793446Smrj 						break;
1803446Smrj 				}
1810Sstevel@tonic-gate 			} else {
1824503Ssudheer 				if (pcb->pcb_rupdate == 1) {
1833446Smrj 					if (pcb->pcb_fs == LWPFS_SEL)
1843446Smrj 						break;
1853446Smrj 				} else {
1863446Smrj 					if (rp->r_fs == LWPFS_SEL)
1873446Smrj 						break;
1883446Smrj 				}
1890Sstevel@tonic-gate 			}
1900Sstevel@tonic-gate 		}
1910Sstevel@tonic-gate 		error = EINVAL;
1920Sstevel@tonic-gate 		break;
1930Sstevel@tonic-gate 	case _LWP_GSBASE:
1940Sstevel@tonic-gate 		if ((sbase = pcb->pcb_gsbase) != 0) {
1953446Smrj 			if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
1964503Ssudheer 				if (pcb->pcb_rupdate == 1) {
1973446Smrj 					if (pcb->pcb_gs == 0)
1983446Smrj 						break;
1993446Smrj 				} else {
2003446Smrj 					if (rp->r_gs == 0)
2013446Smrj 						break;
2023446Smrj 				}
2030Sstevel@tonic-gate 			} else {
2044503Ssudheer 				if (pcb->pcb_rupdate == 1) {
2053446Smrj 					if (pcb->pcb_gs == LWPGS_SEL)
2063446Smrj 						break;
2073446Smrj 				} else {
2083446Smrj 					if (rp->r_gs == LWPGS_SEL)
2093446Smrj 						break;
2103446Smrj 				}
2110Sstevel@tonic-gate 			}
2120Sstevel@tonic-gate 		}
2130Sstevel@tonic-gate 		error = EINVAL;
2140Sstevel@tonic-gate 		break;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate #elif defined(__i386)
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	case _LWP_FSBASE:
2190Sstevel@tonic-gate 		if (rp->r_fs == LWPFS_SEL) {
2200Sstevel@tonic-gate 			sbase = USEGD_GETBASE(&pcb->pcb_fsdesc);
2210Sstevel@tonic-gate 			break;
2220Sstevel@tonic-gate 		}
2230Sstevel@tonic-gate 		error = EINVAL;
2240Sstevel@tonic-gate 		break;
2250Sstevel@tonic-gate 	case _LWP_GSBASE:
2260Sstevel@tonic-gate 		if (rp->r_gs == LWPGS_SEL) {
2270Sstevel@tonic-gate 			sbase = USEGD_GETBASE(&pcb->pcb_gsdesc);
2280Sstevel@tonic-gate 			break;
2290Sstevel@tonic-gate 		}
2300Sstevel@tonic-gate 		error = EINVAL;
2310Sstevel@tonic-gate 		break;
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate #endif	/* __i386 */
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	default:
2360Sstevel@tonic-gate 		error = ENOTSUP;
2370Sstevel@tonic-gate 		break;
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 	kpreempt_enable();
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	if (error != 0)
2420Sstevel@tonic-gate 		return (error);
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
2450Sstevel@tonic-gate 		if (sulword((void *)base, sbase) == -1)
2460Sstevel@tonic-gate 			error = EFAULT;
2470Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL)
2480Sstevel@tonic-gate 	} else {
2490Sstevel@tonic-gate 		if (suword32((void *)base, (uint32_t)sbase) == -1)
2500Sstevel@tonic-gate 			error = EFAULT;
2510Sstevel@tonic-gate #endif
2520Sstevel@tonic-gate 	}
2530Sstevel@tonic-gate 	return (error);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate /*
2570Sstevel@tonic-gate  * libc-private syscall for managing per-lwp %gs and %fs segment base values.
2580Sstevel@tonic-gate  */
2590Sstevel@tonic-gate int
syslwp_private(int cmd,int which,uintptr_t base)2600Sstevel@tonic-gate syslwp_private(int cmd, int which, uintptr_t base)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
2630Sstevel@tonic-gate 	int res, error;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	switch (cmd) {
2660Sstevel@tonic-gate 	case _LWP_SETPRIVATE:
2670Sstevel@tonic-gate 		res = lwp_setprivate(lwp, which, base);
2680Sstevel@tonic-gate 		return (res < 0 ? set_errno(ENOTSUP) : res);
2690Sstevel@tonic-gate 	case _LWP_GETPRIVATE:
2700Sstevel@tonic-gate 		error = lwp_getprivate(lwp, which, base);
2710Sstevel@tonic-gate 		return (error != 0 ? set_errno(error) : error);
2720Sstevel@tonic-gate 	default:
2730Sstevel@tonic-gate 		return (set_errno(ENOTSUP));
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate }
276