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]
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>
31 #include <sys/sysmacros.h>
32 #include <sys/cpuvar.h>
33 #include <sys/systm.h>
34 #include <sys/thread.h>
36 #include <sys/segments.h>
37 #include <sys/privregs.h>
38 #include <sys/cmn_err.h>
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
;
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
64 * to work, which is needed by emulators for legacy application
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
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
;
83 ASSERT(t
->t_post_sys
);
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 */
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
;
97 gdt_update_usegd(GDT_LWPFS
, &pcb
->pcb_fsdesc
);
99 pcb
->pcb_fsbase
= base
;
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 */
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
;
112 gdt_update_usegd(GDT_LWPGS
, &pcb
->pcb_gsdesc
);
114 pcb
->pcb_gsbase
= base
;
121 #elif defined(__i386)
124 * 32-bit processes point to the per-cpu GDT segment
125 * descriptors that are virtualized to the lwp.
130 set_usegd(&pcb
->pcb_fsdesc
, (void *)base
, -1,
131 SDT_MEMRWA
, SEL_UPL
, SDP_PAGES
, SDP_OP32
);
133 gdt_update_usegd(GDT_LWPFS
, &pcb
->pcb_fsdesc
);
135 rval
= rp
->r_fs
= LWPFS_SEL
;
138 set_usegd(&pcb
->pcb_gsdesc
, (void *)base
, -1,
139 SDT_MEMRWA
, SEL_UPL
, SDP_PAGES
, SDP_OP32
);
141 gdt_update_usegd(GDT_LWPGS
, &pcb
->pcb_gsdesc
);
143 rval
= rp
->r_gs
= LWPGS_SEL
;
158 lwp_getprivate(klwp_t
*lwp
, int which
, uintptr_t base
)
160 pcb_t
*pcb
= &lwp
->lwp_pcb
;
161 struct regs
*rp
= lwptoregs(lwp
);
165 ASSERT(lwptot(lwp
) == curthread
);
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)
182 if (pcb
->pcb_rupdate
== 1) {
183 if (pcb
->pcb_fs
== LWPFS_SEL
)
186 if (rp
->r_fs
== LWPFS_SEL
)
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)
204 if (pcb
->pcb_rupdate
== 1) {
205 if (pcb
->pcb_gs
== LWPGS_SEL
)
208 if (rp
->r_gs
== LWPGS_SEL
)
216 #elif defined(__i386)
219 if (rp
->r_fs
== LWPFS_SEL
) {
220 sbase
= USEGD_GETBASE(&pcb
->pcb_fsdesc
);
226 if (rp
->r_gs
== LWPGS_SEL
) {
227 sbase
= USEGD_GETBASE(&pcb
->pcb_gsdesc
);
244 if (lwp_getdatamodel(lwp
) == DATAMODEL_NATIVE
) {
245 if (sulword((void *)base
, sbase
) == -1)
247 #if defined(_SYSCALL32_IMPL)
249 if (suword32((void *)base
, (uint32_t)sbase
) == -1)
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
);
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
);
273 return (set_errno(ENOTSUP
));