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