17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22ae115bc7Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/param.h> 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/disp.h> 317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 327c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 337c478bd9Sstevel@tonic-gate #include <sys/systm.h> 347c478bd9Sstevel@tonic-gate #include <sys/thread.h> 357c478bd9Sstevel@tonic-gate #include <sys/lwp.h> 367c478bd9Sstevel@tonic-gate #include <sys/segments.h> 377c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 387c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate int 417c478bd9Sstevel@tonic-gate lwp_setprivate(klwp_t *lwp, int which, uintptr_t base) 427c478bd9Sstevel@tonic-gate { 437c478bd9Sstevel@tonic-gate pcb_t *pcb = &lwp->lwp_pcb; 447c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 457c478bd9Sstevel@tonic-gate kthread_t *t = lwptot(lwp); 467c478bd9Sstevel@tonic-gate int thisthread = t == curthread; 477c478bd9Sstevel@tonic-gate int rval; 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate if (thisthread) 507c478bd9Sstevel@tonic-gate kpreempt_disable(); 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #if defined(__amd64) 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* 557c478bd9Sstevel@tonic-gate * 32-bit compatibility processes point to the per-cpu GDT segment 567c478bd9Sstevel@tonic-gate * descriptors that are virtualized to the lwp. That allows 32-bit 577c478bd9Sstevel@tonic-gate * programs to mess with %fs and %gs; in particular it allows 587c478bd9Sstevel@tonic-gate * things like this: 597c478bd9Sstevel@tonic-gate * 607c478bd9Sstevel@tonic-gate * movw %gs, %ax 617c478bd9Sstevel@tonic-gate * ... 627c478bd9Sstevel@tonic-gate * movw %ax, %gs 637c478bd9Sstevel@tonic-gate * 647c478bd9Sstevel@tonic-gate * to work, which is needed by emulators for legacy application 657c478bd9Sstevel@tonic-gate * environments .. 667c478bd9Sstevel@tonic-gate * 67ae115bc7Smrj * 64-bit processes may also point to a per-cpu GDT segment descriptor 687c478bd9Sstevel@tonic-gate * virtualized to the lwp. However the descriptor base is forced 697c478bd9Sstevel@tonic-gate * to zero (because we can't express the full 64-bit address range 707c478bd9Sstevel@tonic-gate * in a long mode descriptor), so don't reload segment registers 71ae115bc7Smrj * in a 64-bit program! 64-bit processes must have selector values 72ae115bc7Smrj * of zero for %fs and %gs to use the 64-bit fs_base and gs_base 73ae115bc7Smrj * respectively. 747c478bd9Sstevel@tonic-gate */ 757712e92cSsudheer if (pcb->pcb_rupdate == 0) { 767c478bd9Sstevel@tonic-gate pcb->pcb_ds = rp->r_ds; 777c478bd9Sstevel@tonic-gate pcb->pcb_es = rp->r_es; 787c478bd9Sstevel@tonic-gate pcb->pcb_fs = rp->r_fs; 797c478bd9Sstevel@tonic-gate pcb->pcb_gs = rp->r_gs; 807712e92cSsudheer pcb->pcb_rupdate = 1; 817c478bd9Sstevel@tonic-gate t->t_post_sys = 1; 827c478bd9Sstevel@tonic-gate } 837c478bd9Sstevel@tonic-gate ASSERT(t->t_post_sys); 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate switch (which) { 867c478bd9Sstevel@tonic-gate case _LWP_FSBASE: 87ae115bc7Smrj if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) { 887c478bd9Sstevel@tonic-gate set_usegd(&pcb->pcb_fsdesc, SDP_LONG, 0, 0, 897c478bd9Sstevel@tonic-gate SDT_MEMRWA, SEL_UPL, SDP_BYTES, SDP_OP32); 90ae115bc7Smrj rval = pcb->pcb_fs = 0; /* null gdt descriptor */ 91ae115bc7Smrj } else { 927c478bd9Sstevel@tonic-gate set_usegd(&pcb->pcb_fsdesc, SDP_SHORT, (void *)base, -1, 937c478bd9Sstevel@tonic-gate SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32); 94ae115bc7Smrj rval = pcb->pcb_fs = LWPFS_SEL; 95ae115bc7Smrj } 967c478bd9Sstevel@tonic-gate if (thisthread) 97*843e1988Sjohnlev gdt_update_usegd(GDT_LWPFS, &pcb->pcb_fsdesc); 98*843e1988Sjohnlev 997c478bd9Sstevel@tonic-gate pcb->pcb_fsbase = base; 1007c478bd9Sstevel@tonic-gate break; 1017c478bd9Sstevel@tonic-gate case _LWP_GSBASE: 102ae115bc7Smrj if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) { 1037c478bd9Sstevel@tonic-gate set_usegd(&pcb->pcb_gsdesc, SDP_LONG, 0, 0, 1047c478bd9Sstevel@tonic-gate SDT_MEMRWA, SEL_UPL, SDP_BYTES, SDP_OP32); 105ae115bc7Smrj rval = pcb->pcb_gs = 0; /* null gdt descriptor */ 106ae115bc7Smrj } else { 1077c478bd9Sstevel@tonic-gate set_usegd(&pcb->pcb_gsdesc, SDP_SHORT, (void *)base, -1, 1087c478bd9Sstevel@tonic-gate SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32); 109ae115bc7Smrj rval = pcb->pcb_gs = LWPGS_SEL; 110ae115bc7Smrj } 1117c478bd9Sstevel@tonic-gate if (thisthread) 112*843e1988Sjohnlev gdt_update_usegd(GDT_LWPGS, &pcb->pcb_gsdesc); 113*843e1988Sjohnlev 1147c478bd9Sstevel@tonic-gate pcb->pcb_gsbase = base; 1157c478bd9Sstevel@tonic-gate break; 1167c478bd9Sstevel@tonic-gate default: 1177c478bd9Sstevel@tonic-gate rval = -1; 1187c478bd9Sstevel@tonic-gate break; 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate #elif defined(__i386) 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 124ae115bc7Smrj * 32-bit processes point to the per-cpu GDT segment 1257c478bd9Sstevel@tonic-gate * descriptors that are virtualized to the lwp. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate switch (which) { 1297c478bd9Sstevel@tonic-gate case _LWP_FSBASE: 1307c478bd9Sstevel@tonic-gate set_usegd(&pcb->pcb_fsdesc, (void *)base, -1, 1317c478bd9Sstevel@tonic-gate SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32); 1327c478bd9Sstevel@tonic-gate if (thisthread) 133*843e1988Sjohnlev gdt_update_usegd(GDT_LWPFS, &pcb->pcb_fsdesc); 134*843e1988Sjohnlev 1357c478bd9Sstevel@tonic-gate rval = rp->r_fs = LWPFS_SEL; 1367c478bd9Sstevel@tonic-gate break; 1377c478bd9Sstevel@tonic-gate case _LWP_GSBASE: 1387c478bd9Sstevel@tonic-gate set_usegd(&pcb->pcb_gsdesc, (void *)base, -1, 1397c478bd9Sstevel@tonic-gate SDT_MEMRWA, SEL_UPL, SDP_PAGES, SDP_OP32); 1407c478bd9Sstevel@tonic-gate if (thisthread) 141*843e1988Sjohnlev gdt_update_usegd(GDT_LWPGS, &pcb->pcb_gsdesc); 142*843e1988Sjohnlev 1437c478bd9Sstevel@tonic-gate rval = rp->r_gs = LWPGS_SEL; 1447c478bd9Sstevel@tonic-gate break; 1457c478bd9Sstevel@tonic-gate default: 1467c478bd9Sstevel@tonic-gate rval = -1; 1477c478bd9Sstevel@tonic-gate break; 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate #endif /* __i386 */ 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate if (thisthread) 1537c478bd9Sstevel@tonic-gate kpreempt_enable(); 1547c478bd9Sstevel@tonic-gate return (rval); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate static int 1587c478bd9Sstevel@tonic-gate lwp_getprivate(klwp_t *lwp, int which, uintptr_t base) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate pcb_t *pcb = &lwp->lwp_pcb; 1617c478bd9Sstevel@tonic-gate struct regs *rp = lwptoregs(lwp); 1627c478bd9Sstevel@tonic-gate uintptr_t sbase; 1637c478bd9Sstevel@tonic-gate int error = 0; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate ASSERT(lwptot(lwp) == curthread); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate kpreempt_disable(); 1687c478bd9Sstevel@tonic-gate switch (which) { 1697c478bd9Sstevel@tonic-gate #if defined(__amd64) 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate case _LWP_FSBASE: 1727c478bd9Sstevel@tonic-gate if ((sbase = pcb->pcb_fsbase) != 0) { 173ae115bc7Smrj if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) { 1747712e92cSsudheer if (pcb->pcb_rupdate == 1) { 175ae115bc7Smrj if (pcb->pcb_fs == 0) 176ae115bc7Smrj break; 177ae115bc7Smrj } else { 178ae115bc7Smrj if (rp->r_fs == 0) 179ae115bc7Smrj break; 180ae115bc7Smrj } 181ae115bc7Smrj } else { 1827712e92cSsudheer if (pcb->pcb_rupdate == 1) { 1837c478bd9Sstevel@tonic-gate if (pcb->pcb_fs == LWPFS_SEL) 1847c478bd9Sstevel@tonic-gate break; 1857c478bd9Sstevel@tonic-gate } else { 1867c478bd9Sstevel@tonic-gate if (rp->r_fs == LWPFS_SEL) 1877c478bd9Sstevel@tonic-gate break; 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate } 190ae115bc7Smrj } 1917c478bd9Sstevel@tonic-gate error = EINVAL; 1927c478bd9Sstevel@tonic-gate break; 1937c478bd9Sstevel@tonic-gate case _LWP_GSBASE: 1947c478bd9Sstevel@tonic-gate if ((sbase = pcb->pcb_gsbase) != 0) { 195ae115bc7Smrj if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) { 1967712e92cSsudheer if (pcb->pcb_rupdate == 1) { 197ae115bc7Smrj if (pcb->pcb_gs == 0) 198ae115bc7Smrj break; 199ae115bc7Smrj } else { 200ae115bc7Smrj if (rp->r_gs == 0) 201ae115bc7Smrj break; 202ae115bc7Smrj } 203ae115bc7Smrj } else { 2047712e92cSsudheer if (pcb->pcb_rupdate == 1) { 2057c478bd9Sstevel@tonic-gate if (pcb->pcb_gs == LWPGS_SEL) 2067c478bd9Sstevel@tonic-gate break; 2077c478bd9Sstevel@tonic-gate } else { 2087c478bd9Sstevel@tonic-gate if (rp->r_gs == LWPGS_SEL) 2097c478bd9Sstevel@tonic-gate break; 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate } 212ae115bc7Smrj } 2137c478bd9Sstevel@tonic-gate error = EINVAL; 2147c478bd9Sstevel@tonic-gate break; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate #elif defined(__i386) 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate case _LWP_FSBASE: 2197c478bd9Sstevel@tonic-gate if (rp->r_fs == LWPFS_SEL) { 2207c478bd9Sstevel@tonic-gate sbase = USEGD_GETBASE(&pcb->pcb_fsdesc); 2217c478bd9Sstevel@tonic-gate break; 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate error = EINVAL; 2247c478bd9Sstevel@tonic-gate break; 2257c478bd9Sstevel@tonic-gate case _LWP_GSBASE: 2267c478bd9Sstevel@tonic-gate if (rp->r_gs == LWPGS_SEL) { 2277c478bd9Sstevel@tonic-gate sbase = USEGD_GETBASE(&pcb->pcb_gsdesc); 2287c478bd9Sstevel@tonic-gate break; 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate error = EINVAL; 2317c478bd9Sstevel@tonic-gate break; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate #endif /* __i386 */ 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate default: 2367c478bd9Sstevel@tonic-gate error = ENOTSUP; 2377c478bd9Sstevel@tonic-gate break; 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate kpreempt_enable(); 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate if (error != 0) 2427c478bd9Sstevel@tonic-gate return (error); 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate if (lwp_getdatamodel(lwp) == DATAMODEL_NATIVE) { 2457c478bd9Sstevel@tonic-gate if (sulword((void *)base, sbase) == -1) 2467c478bd9Sstevel@tonic-gate error = EFAULT; 2477c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) 2487c478bd9Sstevel@tonic-gate } else { 2497c478bd9Sstevel@tonic-gate if (suword32((void *)base, (uint32_t)sbase) == -1) 2507c478bd9Sstevel@tonic-gate error = EFAULT; 2517c478bd9Sstevel@tonic-gate #endif 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate return (error); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate /* 2577c478bd9Sstevel@tonic-gate * libc-private syscall for managing per-lwp %gs and %fs segment base values. 2587c478bd9Sstevel@tonic-gate */ 2597c478bd9Sstevel@tonic-gate int 2607c478bd9Sstevel@tonic-gate syslwp_private(int cmd, int which, uintptr_t base) 2617c478bd9Sstevel@tonic-gate { 2627c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 2637c478bd9Sstevel@tonic-gate int res, error; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate switch (cmd) { 2667c478bd9Sstevel@tonic-gate case _LWP_SETPRIVATE: 2677c478bd9Sstevel@tonic-gate res = lwp_setprivate(lwp, which, base); 2687c478bd9Sstevel@tonic-gate return (res < 0 ? set_errno(ENOTSUP) : res); 2697c478bd9Sstevel@tonic-gate case _LWP_GETPRIVATE: 2707c478bd9Sstevel@tonic-gate error = lwp_getprivate(lwp, which, base); 2717c478bd9Sstevel@tonic-gate return (error != 0 ? set_errno(error) : error); 2727c478bd9Sstevel@tonic-gate default: 2737c478bd9Sstevel@tonic-gate return (set_errno(ENOTSUP)); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate } 276