xref: /illumos-gate/usr/src/uts/intel/syscall/lwp_private.c (revision f0089e391b2bc4be2755f1a1b51fb4cd9b8f3988)
1*f0089e39SRichard Lowe /*
2*f0089e39SRichard Lowe  * CDDL HEADER START
3*f0089e39SRichard Lowe  *
4*f0089e39SRichard Lowe  * The contents of this file are subject to the terms of the
5*f0089e39SRichard Lowe  * Common Development and Distribution License (the "License").
6*f0089e39SRichard Lowe  * You may not use this file except in compliance with the License.
7*f0089e39SRichard Lowe  *
8*f0089e39SRichard Lowe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*f0089e39SRichard Lowe  * or http://www.opensolaris.org/os/licensing.
10*f0089e39SRichard Lowe  * See the License for the specific language governing permissions
11*f0089e39SRichard Lowe  * and limitations under the License.
12*f0089e39SRichard Lowe  *
13*f0089e39SRichard Lowe  * When distributing Covered Code, include this CDDL HEADER in each
14*f0089e39SRichard Lowe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*f0089e39SRichard Lowe  * If applicable, add the following below this CDDL HEADER, with the
16*f0089e39SRichard Lowe  * fields enclosed by brackets "[]" replaced with your own identifying
17*f0089e39SRichard Lowe  * information: Portions Copyright [yyyy] [name of copyright owner]
18*f0089e39SRichard Lowe  *
19*f0089e39SRichard Lowe  * CDDL HEADER END
20*f0089e39SRichard Lowe  */
21*f0089e39SRichard Lowe /*
22*f0089e39SRichard Lowe  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*f0089e39SRichard Lowe  * Use is subject to license terms.
24*f0089e39SRichard Lowe  * Copyright (c) 2018, Joyent, Inc.
25*f0089e39SRichard Lowe  */
26*f0089e39SRichard Lowe 
27*f0089e39SRichard Lowe #include <sys/param.h>
28*f0089e39SRichard Lowe #include <sys/types.h>
29*f0089e39SRichard Lowe #include <sys/disp.h>
30*f0089e39SRichard Lowe #include <sys/sysmacros.h>
31*f0089e39SRichard Lowe #include <sys/cpuvar.h>
32*f0089e39SRichard Lowe #include <sys/systm.h>
33*f0089e39SRichard Lowe #include <sys/thread.h>
34*f0089e39SRichard Lowe #include <sys/lwp.h>
35*f0089e39SRichard Lowe #include <sys/segments.h>
36*f0089e39SRichard Lowe #include <sys/privregs.h>
37*f0089e39SRichard Lowe #include <sys/cmn_err.h>
38*f0089e39SRichard Lowe 
39*f0089e39SRichard Lowe int
lwp_setprivate(klwp_t * lwp,int which,uintptr_t base)40*f0089e39SRichard Lowe lwp_setprivate(klwp_t *lwp, int which, uintptr_t base)
41*f0089e39SRichard Lowe {
42*f0089e39SRichard Lowe 	pcb_t *pcb = &lwp->lwp_pcb;
43*f0089e39SRichard Lowe 	struct regs *rp = lwptoregs(lwp);
44*f0089e39SRichard Lowe 	kthread_t *t = lwptot(lwp);
45*f0089e39SRichard Lowe 	int thisthread = t == curthread;
46*f0089e39SRichard Lowe 	int rval;
47*f0089e39SRichard Lowe 
48*f0089e39SRichard Lowe 	if (thisthread)
49*f0089e39SRichard Lowe 		kpreempt_disable();
50*f0089e39SRichard Lowe 
51*f0089e39SRichard Lowe 
52*f0089e39SRichard Lowe 	/*
53*f0089e39SRichard Lowe 	 * 32-bit compatibility processes point to the per-cpu GDT segment
54*f0089e39SRichard Lowe 	 * descriptors that are virtualized to the lwp.  That allows 32-bit
55*f0089e39SRichard Lowe 	 * programs to mess with %fs and %gs; in particular it allows
56*f0089e39SRichard Lowe 	 * things like this:
57*f0089e39SRichard Lowe 	 *
58*f0089e39SRichard Lowe 	 *	movw	%gs, %ax
59*f0089e39SRichard Lowe 	 *	...
60*f0089e39SRichard Lowe 	 *	movw	%ax, %gs
61*f0089e39SRichard Lowe 	 *
62*f0089e39SRichard Lowe 	 * to work, which is needed by emulators for legacy application
63*f0089e39SRichard Lowe 	 * environments ..
64*f0089e39SRichard Lowe 	 *
65*f0089e39SRichard Lowe 	 * 64-bit processes may also point to a per-cpu GDT segment descriptor
66*f0089e39SRichard Lowe 	 * virtualized to the lwp.  However the descriptor base is forced
67*f0089e39SRichard Lowe 	 * to zero (because we can't express the full 64-bit address range
68*f0089e39SRichard Lowe 	 * in a long mode descriptor), so don't reload segment registers
69*f0089e39SRichard Lowe 	 * in a 64-bit program! 64-bit processes must have selector values
70*f0089e39SRichard Lowe 	 * of zero for %fs and %gs to use the 64-bit fs_base and gs_base
71*f0089e39SRichard Lowe 	 * respectively.
72*f0089e39SRichard Lowe 	 */
73*f0089e39SRichard Lowe 	if (!PCB_NEED_UPDATE_SEGS(pcb)) {
74*f0089e39SRichard Lowe 		pcb->pcb_ds = rp->r_ds;
75*f0089e39SRichard Lowe 		pcb->pcb_es = rp->r_es;
76*f0089e39SRichard Lowe 		pcb->pcb_fs = rp->r_fs;
77*f0089e39SRichard Lowe 		pcb->pcb_gs = rp->r_gs;
78*f0089e39SRichard Lowe 		PCB_SET_UPDATE_SEGS(pcb);
79*f0089e39SRichard Lowe 		t->t_post_sys = 1;
80*f0089e39SRichard Lowe 	}
81*f0089e39SRichard Lowe 	ASSERT(t->t_post_sys);
82*f0089e39SRichard Lowe 
83*f0089e39SRichard Lowe 	switch (which) {
84*f0089e39SRichard Lowe 	case _LWP_FSBASE:
85*f0089e39SRichard Lowe 		if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
86*f0089e39SRichard Lowe 			set_usegd(&pcb->pcb_fsdesc, SDP_LONG, 0, 0,
87*f0089e39SRichard Lowe 			    SDT_MEMRWA, SEL_UPL, SDP_BYTES, SDP_OP32);
88*f0089e39SRichard Lowe 			rval = pcb->pcb_fs = 0;	/* null gdt descriptor */
89*f0089e39SRichard Lowe 		} else {
90*f0089e39SRichard Lowe 			set_usegd(&pcb->pcb_fsdesc, SDP_SHORT, (void *)base, -1,
91*f0089e39SRichard Lowe 			    SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
92*f0089e39SRichard Lowe 			rval = pcb->pcb_fs = LWPFS_SEL;
93*f0089e39SRichard Lowe 		}
94*f0089e39SRichard Lowe 		if (thisthread)
95*f0089e39SRichard Lowe 			gdt_update_usegd(GDT_LWPFS, &pcb->pcb_fsdesc);
96*f0089e39SRichard Lowe 
97*f0089e39SRichard Lowe 		pcb->pcb_fsbase = base;
98*f0089e39SRichard Lowe 		break;
99*f0089e39SRichard Lowe 	case _LWP_GSBASE:
100*f0089e39SRichard Lowe 		if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
101*f0089e39SRichard Lowe 			set_usegd(&pcb->pcb_gsdesc, SDP_LONG, 0, 0,
102*f0089e39SRichard Lowe 			    SDT_MEMRWA, SEL_UPL, SDP_BYTES, SDP_OP32);
103*f0089e39SRichard Lowe 			rval = pcb->pcb_gs = 0;	/* null gdt descriptor */
104*f0089e39SRichard Lowe 		} else {
105*f0089e39SRichard Lowe 			set_usegd(&pcb->pcb_gsdesc, SDP_SHORT, (void *)base, -1,
106*f0089e39SRichard Lowe 			    SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
107*f0089e39SRichard Lowe 			rval = pcb->pcb_gs = LWPGS_SEL;
108*f0089e39SRichard Lowe 		}
109*f0089e39SRichard Lowe 		if (thisthread)
110*f0089e39SRichard Lowe 			gdt_update_usegd(GDT_LWPGS, &pcb->pcb_gsdesc);
111*f0089e39SRichard Lowe 
112*f0089e39SRichard Lowe 		pcb->pcb_gsbase = base;
113*f0089e39SRichard Lowe 		break;
114*f0089e39SRichard Lowe 	default:
115*f0089e39SRichard Lowe 		rval = -1;
116*f0089e39SRichard Lowe 		break;
117*f0089e39SRichard Lowe 	}
118*f0089e39SRichard Lowe 
119*f0089e39SRichard Lowe 	if (thisthread)
120*f0089e39SRichard Lowe 		kpreempt_enable();
121*f0089e39SRichard Lowe 	return (rval);
122*f0089e39SRichard Lowe }
123*f0089e39SRichard Lowe 
124*f0089e39SRichard Lowe static int
lwp_getprivate(klwp_t * lwp,int which,uintptr_t base)125*f0089e39SRichard Lowe lwp_getprivate(klwp_t *lwp, int which, uintptr_t base)
126*f0089e39SRichard Lowe {
127*f0089e39SRichard Lowe 	pcb_t *pcb = &lwp->lwp_pcb;
128*f0089e39SRichard Lowe 	struct regs *rp = lwptoregs(lwp);
129*f0089e39SRichard Lowe 	uintptr_t sbase;
130*f0089e39SRichard Lowe 	int error = 0;
131*f0089e39SRichard Lowe 
132*f0089e39SRichard Lowe 	ASSERT(lwptot(lwp) == curthread);
133*f0089e39SRichard Lowe 
134*f0089e39SRichard Lowe 	kpreempt_disable();
135*f0089e39SRichard Lowe 	switch (which) {
136*f0089e39SRichard Lowe 	case _LWP_FSBASE:
137*f0089e39SRichard Lowe 		if ((sbase = pcb->pcb_fsbase) != 0) {
138*f0089e39SRichard Lowe 			if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
139*f0089e39SRichard Lowe 				if (PCB_NEED_UPDATE_SEGS(pcb)) {
140*f0089e39SRichard Lowe 					if (pcb->pcb_fs == 0)
141*f0089e39SRichard Lowe 						break;
142*f0089e39SRichard Lowe 				} else {
143*f0089e39SRichard Lowe 					if (rp->r_fs == 0)
144*f0089e39SRichard Lowe 						break;
145*f0089e39SRichard Lowe 				}
146*f0089e39SRichard Lowe 			} else {
147*f0089e39SRichard Lowe 				if (PCB_NEED_UPDATE_SEGS(pcb)) {
148*f0089e39SRichard Lowe 					if (pcb->pcb_fs == LWPFS_SEL)
149*f0089e39SRichard Lowe 						break;
150*f0089e39SRichard Lowe 				} else {
151*f0089e39SRichard Lowe 					if (rp->r_fs == LWPFS_SEL)
152*f0089e39SRichard Lowe 						break;
153*f0089e39SRichard Lowe 				}
154*f0089e39SRichard Lowe 			}
155*f0089e39SRichard Lowe 		}
156*f0089e39SRichard Lowe 		error = EINVAL;
157*f0089e39SRichard Lowe 		break;
158*f0089e39SRichard Lowe 	case _LWP_GSBASE:
159*f0089e39SRichard Lowe 		if ((sbase = pcb->pcb_gsbase) != 0) {
160*f0089e39SRichard Lowe 			if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
161*f0089e39SRichard Lowe 				if (PCB_NEED_UPDATE_SEGS(pcb)) {
162*f0089e39SRichard Lowe 					if (pcb->pcb_gs == 0)
163*f0089e39SRichard Lowe 						break;
164*f0089e39SRichard Lowe 				} else {
165*f0089e39SRichard Lowe 					if (rp->r_gs == 0)
166*f0089e39SRichard Lowe 						break;
167*f0089e39SRichard Lowe 				}
168*f0089e39SRichard Lowe 			} else {
169*f0089e39SRichard Lowe 				if (PCB_NEED_UPDATE_SEGS(pcb)) {
170*f0089e39SRichard Lowe 					if (pcb->pcb_gs == LWPGS_SEL)
171*f0089e39SRichard Lowe 						break;
172*f0089e39SRichard Lowe 				} else {
173*f0089e39SRichard Lowe 					if (rp->r_gs == LWPGS_SEL)
174*f0089e39SRichard Lowe 						break;
175*f0089e39SRichard Lowe 				}
176*f0089e39SRichard Lowe 			}
177*f0089e39SRichard Lowe 		}
178*f0089e39SRichard Lowe 		error = EINVAL;
179*f0089e39SRichard Lowe 		break;
180*f0089e39SRichard Lowe 
181*f0089e39SRichard Lowe 
182*f0089e39SRichard Lowe 	default:
183*f0089e39SRichard Lowe 		error = ENOTSUP;
184*f0089e39SRichard Lowe 		break;
185*f0089e39SRichard Lowe 	}
186*f0089e39SRichard Lowe 	kpreempt_enable();
187*f0089e39SRichard Lowe 
188*f0089e39SRichard Lowe 	if (error != 0)
189*f0089e39SRichard Lowe 		return (error);
190*f0089e39SRichard Lowe 
191*f0089e39SRichard Lowe 	if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
192*f0089e39SRichard Lowe 		if (sulword((void *)base, sbase) == -1)
193*f0089e39SRichard Lowe 			error = EFAULT;
194*f0089e39SRichard Lowe #if defined(_SYSCALL32_IMPL)
195*f0089e39SRichard Lowe 	} else {
196*f0089e39SRichard Lowe 		if (suword32((void *)base, (uint32_t)sbase) == -1)
197*f0089e39SRichard Lowe 			error = EFAULT;
198*f0089e39SRichard Lowe #endif
199*f0089e39SRichard Lowe 	}
200*f0089e39SRichard Lowe 	return (error);
201*f0089e39SRichard Lowe }
202*f0089e39SRichard Lowe 
203*f0089e39SRichard Lowe /*
204*f0089e39SRichard Lowe  * libc-private syscall for managing per-lwp %gs and %fs segment base values.
205*f0089e39SRichard Lowe  */
206*f0089e39SRichard Lowe int
syslwp_private(int cmd,int which,uintptr_t base)207*f0089e39SRichard Lowe syslwp_private(int cmd, int which, uintptr_t base)
208*f0089e39SRichard Lowe {
209*f0089e39SRichard Lowe 	klwp_t *lwp = ttolwp(curthread);
210*f0089e39SRichard Lowe 	int res, error;
211*f0089e39SRichard Lowe 
212*f0089e39SRichard Lowe 	switch (cmd) {
213*f0089e39SRichard Lowe 	case _LWP_SETPRIVATE:
214*f0089e39SRichard Lowe 		res = lwp_setprivate(lwp, which, base);
215*f0089e39SRichard Lowe 		return (res < 0 ? set_errno(ENOTSUP) : res);
216*f0089e39SRichard Lowe 	case _LWP_GETPRIVATE:
217*f0089e39SRichard Lowe 		error = lwp_getprivate(lwp, which, base);
218*f0089e39SRichard Lowe 		return (error != 0 ? set_errno(error) : error);
219*f0089e39SRichard Lowe 	default:
220*f0089e39SRichard Lowe 		return (set_errno(ENOTSUP));
221*f0089e39SRichard Lowe 	}
222*f0089e39SRichard Lowe }
223