dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / arch / x86 / kernel / syscall / lwp_private.c
blob79e9076ee03cb2a1ae9cd7a0aee19d17af3f92e0
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/disp.h>
31 #include <sys/sysmacros.h>
32 #include <sys/cpuvar.h>
33 #include <sys/systm.h>
34 #include <sys/thread.h>
35 #include <sys/lwp.h>
36 #include <sys/segments.h>
37 #include <sys/privregs.h>
38 #include <sys/cmn_err.h>
40 int
41 lwp_setprivate(klwp_t *lwp, int which, uintptr_t base)
43 pcb_t *pcb = &lwp->lwp_pcb;
44 struct regs *rp = lwptoregs(lwp);
45 kthread_t *t = lwptot(lwp);
46 int thisthread = t == curthread;
47 int rval;
49 if (thisthread)
50 kpreempt_disable();
52 #if defined(__amd64)
55 * 32-bit compatibility processes point to the per-cpu GDT segment
56 * descriptors that are virtualized to the lwp. That allows 32-bit
57 * programs to mess with %fs and %gs; in particular it allows
58 * things like this:
60 * movw %gs, %ax
61 * ...
62 * movw %ax, %gs
64 * to work, which is needed by emulators for legacy application
65 * environments ..
67 * 64-bit processes may also point to a per-cpu GDT segment descriptor
68 * virtualized to the lwp. However the descriptor base is forced
69 * to zero (because we can't express the full 64-bit address range
70 * in a long mode descriptor), so don't reload segment registers
71 * in a 64-bit program! 64-bit processes must have selector values
72 * of zero for %fs and %gs to use the 64-bit fs_base and gs_base
73 * respectively.
75 if (pcb->pcb_rupdate == 0) {
76 pcb->pcb_ds = rp->r_ds;
77 pcb->pcb_es = rp->r_es;
78 pcb->pcb_fs = rp->r_fs;
79 pcb->pcb_gs = rp->r_gs;
80 pcb->pcb_rupdate = 1;
81 t->t_post_sys = 1;
83 ASSERT(t->t_post_sys);
85 switch (which) {
86 case _LWP_FSBASE:
87 if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
88 set_usegd(&pcb->pcb_fsdesc, SDP_LONG, 0, 0,
89 SDT_MEMRWA, SEL_UPL, SDP_BYTES, SDP_OP32);
90 rval = pcb->pcb_fs = 0; /* null gdt descriptor */
91 } else {
92 set_usegd(&pcb->pcb_fsdesc, SDP_SHORT, (void *)base, -1,
93 SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
94 rval = pcb->pcb_fs = LWPFS_SEL;
96 if (thisthread)
97 gdt_update_usegd(GDT_LWPFS, &pcb->pcb_fsdesc);
99 pcb->pcb_fsbase = base;
100 break;
101 case _LWP_GSBASE:
102 if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
103 set_usegd(&pcb->pcb_gsdesc, SDP_LONG, 0, 0,
104 SDT_MEMRWA, SEL_UPL, SDP_BYTES, SDP_OP32);
105 rval = pcb->pcb_gs = 0; /* null gdt descriptor */
106 } else {
107 set_usegd(&pcb->pcb_gsdesc, SDP_SHORT, (void *)base, -1,
108 SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
109 rval = pcb->pcb_gs = LWPGS_SEL;
111 if (thisthread)
112 gdt_update_usegd(GDT_LWPGS, &pcb->pcb_gsdesc);
114 pcb->pcb_gsbase = base;
115 break;
116 default:
117 rval = -1;
118 break;
121 #elif defined(__i386)
124 * 32-bit processes point to the per-cpu GDT segment
125 * descriptors that are virtualized to the lwp.
128 switch (which) {
129 case _LWP_FSBASE:
130 set_usegd(&pcb->pcb_fsdesc, (void *)base, -1,
131 SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
132 if (thisthread)
133 gdt_update_usegd(GDT_LWPFS, &pcb->pcb_fsdesc);
135 rval = rp->r_fs = LWPFS_SEL;
136 break;
137 case _LWP_GSBASE:
138 set_usegd(&pcb->pcb_gsdesc, (void *)base, -1,
139 SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32);
140 if (thisthread)
141 gdt_update_usegd(GDT_LWPGS, &pcb->pcb_gsdesc);
143 rval = rp->r_gs = LWPGS_SEL;
144 break;
145 default:
146 rval = -1;
147 break;
150 #endif /* __i386 */
152 if (thisthread)
153 kpreempt_enable();
154 return (rval);
157 static int
158 lwp_getprivate(klwp_t *lwp, int which, uintptr_t base)
160 pcb_t *pcb = &lwp->lwp_pcb;
161 struct regs *rp = lwptoregs(lwp);
162 uintptr_t sbase;
163 int error = 0;
165 ASSERT(lwptot(lwp) == curthread);
167 kpreempt_disable();
168 switch (which) {
169 #if defined(__amd64)
171 case _LWP_FSBASE:
172 if ((sbase = pcb->pcb_fsbase) != 0) {
173 if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
174 if (pcb->pcb_rupdate == 1) {
175 if (pcb->pcb_fs == 0)
176 break;
177 } else {
178 if (rp->r_fs == 0)
179 break;
181 } else {
182 if (pcb->pcb_rupdate == 1) {
183 if (pcb->pcb_fs == LWPFS_SEL)
184 break;
185 } else {
186 if (rp->r_fs == LWPFS_SEL)
187 break;
191 error = EINVAL;
192 break;
193 case _LWP_GSBASE:
194 if ((sbase = pcb->pcb_gsbase) != 0) {
195 if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
196 if (pcb->pcb_rupdate == 1) {
197 if (pcb->pcb_gs == 0)
198 break;
199 } else {
200 if (rp->r_gs == 0)
201 break;
203 } else {
204 if (pcb->pcb_rupdate == 1) {
205 if (pcb->pcb_gs == LWPGS_SEL)
206 break;
207 } else {
208 if (rp->r_gs == LWPGS_SEL)
209 break;
213 error = EINVAL;
214 break;
216 #elif defined(__i386)
218 case _LWP_FSBASE:
219 if (rp->r_fs == LWPFS_SEL) {
220 sbase = USEGD_GETBASE(&pcb->pcb_fsdesc);
221 break;
223 error = EINVAL;
224 break;
225 case _LWP_GSBASE:
226 if (rp->r_gs == LWPGS_SEL) {
227 sbase = USEGD_GETBASE(&pcb->pcb_gsdesc);
228 break;
230 error = EINVAL;
231 break;
233 #endif /* __i386 */
235 default:
236 error = ENOTSUP;
237 break;
239 kpreempt_enable();
241 if (error != 0)
242 return (error);
244 if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) {
245 if (sulword((void *)base, sbase) == -1)
246 error = EFAULT;
247 #if defined(_SYSCALL32_IMPL)
248 } else {
249 if (suword32((void *)base, (uint32_t)sbase) == -1)
250 error = EFAULT;
251 #endif
253 return (error);
257 * libc-private syscall for managing per-lwp %gs and %fs segment base values.
260 syslwp_private(int cmd, int which, uintptr_t base)
262 klwp_t *lwp = ttolwp(curthread);
263 int res, error;
265 switch (cmd) {
266 case _LWP_SETPRIVATE:
267 res = lwp_setprivate(lwp, which, base);
268 return (res < 0 ? set_errno(ENOTSUP) : res);
269 case _LWP_GETPRIVATE:
270 error = lwp_getprivate(lwp, which, base);
271 return (error != 0 ? set_errno(error) : error);
272 default:
273 return (set_errno(ENOTSUP));