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