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