1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 28*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 29*0Sstevel@tonic-gate /* All Rights Reserved */ 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 32*0Sstevel@tonic-gate /* All Rights Reserved */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate #include <sys/param.h> 37*0Sstevel@tonic-gate #include <sys/types.h> 38*0Sstevel@tonic-gate #include <sys/sysmacros.h> 39*0Sstevel@tonic-gate #include <sys/systm.h> 40*0Sstevel@tonic-gate #include <sys/signal.h> 41*0Sstevel@tonic-gate #include <sys/errno.h> 42*0Sstevel@tonic-gate #include <sys/fault.h> 43*0Sstevel@tonic-gate #include <sys/syscall.h> 44*0Sstevel@tonic-gate #include <sys/cpuvar.h> 45*0Sstevel@tonic-gate #include <sys/sysi86.h> 46*0Sstevel@tonic-gate #include <sys/psw.h> 47*0Sstevel@tonic-gate #include <sys/cred.h> 48*0Sstevel@tonic-gate #include <sys/policy.h> 49*0Sstevel@tonic-gate #include <sys/thread.h> 50*0Sstevel@tonic-gate #include <sys/debug.h> 51*0Sstevel@tonic-gate #include <sys/ontrap.h> 52*0Sstevel@tonic-gate #include <sys/privregs.h> 53*0Sstevel@tonic-gate #include <sys/x86_archext.h> 54*0Sstevel@tonic-gate #include <sys/vmem.h> 55*0Sstevel@tonic-gate #include <sys/kmem.h> 56*0Sstevel@tonic-gate #include <sys/mman.h> 57*0Sstevel@tonic-gate #include <sys/archsystm.h> 58*0Sstevel@tonic-gate #include <vm/hat.h> 59*0Sstevel@tonic-gate #include <vm/as.h> 60*0Sstevel@tonic-gate #include <vm/seg.h> 61*0Sstevel@tonic-gate #include <vm/seg_kmem.h> 62*0Sstevel@tonic-gate #include <vm/faultcode.h> 63*0Sstevel@tonic-gate #include <sys/fp.h> 64*0Sstevel@tonic-gate #include <sys/cmn_err.h> 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate static int setdscr(caddr_t ap); 67*0Sstevel@tonic-gate static void *setup_ldt(proc_t *pp); 68*0Sstevel@tonic-gate static void *ldt_map(proc_t *pp, uint_t seli); 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate extern void rtcsync(void); 71*0Sstevel@tonic-gate extern long ggmtl(void); 72*0Sstevel@tonic-gate extern void sgmtl(long); 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate /* 75*0Sstevel@tonic-gate * sysi86 System Call 76*0Sstevel@tonic-gate */ 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate /* ARGSUSED */ 79*0Sstevel@tonic-gate int 80*0Sstevel@tonic-gate sysi86(short cmd, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) 81*0Sstevel@tonic-gate { 82*0Sstevel@tonic-gate int error = 0; 83*0Sstevel@tonic-gate int c; 84*0Sstevel@tonic-gate proc_t *pp = curproc; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate switch (cmd) { 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* 89*0Sstevel@tonic-gate * The SI86V86 subsystem call of the SYSI86 system call 90*0Sstevel@tonic-gate * supports only one subcode -- V86SC_IOPL. 91*0Sstevel@tonic-gate */ 92*0Sstevel@tonic-gate case SI86V86: 93*0Sstevel@tonic-gate if (arg1 == V86SC_IOPL) { 94*0Sstevel@tonic-gate struct regs *rp = lwptoregs(ttolwp(curthread)); 95*0Sstevel@tonic-gate greg_t oldpl = rp->r_ps & PS_IOPL; 96*0Sstevel@tonic-gate greg_t newpl = arg2 & PS_IOPL; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate /* 99*0Sstevel@tonic-gate * Must be privileged to run this system call 100*0Sstevel@tonic-gate * if giving more io privilege. 101*0Sstevel@tonic-gate */ 102*0Sstevel@tonic-gate if (newpl > oldpl && (error = 103*0Sstevel@tonic-gate secpolicy_sys_config(CRED(), B_FALSE)) != 0) 104*0Sstevel@tonic-gate return (set_errno(error)); 105*0Sstevel@tonic-gate rp->r_ps ^= oldpl ^ newpl; 106*0Sstevel@tonic-gate } else 107*0Sstevel@tonic-gate error = EINVAL; 108*0Sstevel@tonic-gate break; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate /* 111*0Sstevel@tonic-gate * Set a segment descriptor 112*0Sstevel@tonic-gate */ 113*0Sstevel@tonic-gate case SI86DSCR: 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * There are considerable problems here manipulating 116*0Sstevel@tonic-gate * resources shared by many running lwps. Get everyone 117*0Sstevel@tonic-gate * into a safe state before changing the LDT. 118*0Sstevel@tonic-gate */ 119*0Sstevel@tonic-gate if (curthread != pp->p_agenttp && !holdlwps(SHOLDFORK1)) { 120*0Sstevel@tonic-gate error = EINTR; 121*0Sstevel@tonic-gate break; 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate error = setdscr((caddr_t)arg1); 124*0Sstevel@tonic-gate mutex_enter(&pp->p_lock); 125*0Sstevel@tonic-gate if (curthread != pp->p_agenttp) 126*0Sstevel@tonic-gate continuelwps(pp); 127*0Sstevel@tonic-gate mutex_exit(&pp->p_lock); 128*0Sstevel@tonic-gate break; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate case SI86FPHW: 131*0Sstevel@tonic-gate c = fp_kind & 0xff; 132*0Sstevel@tonic-gate if (suword32((void *)arg1, c) == -1) 133*0Sstevel@tonic-gate error = EFAULT; 134*0Sstevel@tonic-gate break; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate case SI86FPSTART: 137*0Sstevel@tonic-gate /* 138*0Sstevel@tonic-gate * arg1 is the address of _fp_hw 139*0Sstevel@tonic-gate * arg2 is the desired x87 FCW value 140*0Sstevel@tonic-gate * arg3 is the desired SSE MXCSR value 141*0Sstevel@tonic-gate * a return value of one means SSE hardware, else none. 142*0Sstevel@tonic-gate */ 143*0Sstevel@tonic-gate c = fp_kind & 0xff; 144*0Sstevel@tonic-gate if (suword32((void *)arg1, c) == -1) { 145*0Sstevel@tonic-gate error = EFAULT; 146*0Sstevel@tonic-gate break; 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate fpsetcw((uint16_t)arg2, (uint32_t)arg3); 149*0Sstevel@tonic-gate return (fp_kind == __FP_SSE ? 1 : 0); 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate /* real time clock management commands */ 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate case WTODC: 154*0Sstevel@tonic-gate if ((error = secpolicy_settime(CRED())) == 0) { 155*0Sstevel@tonic-gate timestruc_t ts; 156*0Sstevel@tonic-gate mutex_enter(&tod_lock); 157*0Sstevel@tonic-gate gethrestime(&ts); 158*0Sstevel@tonic-gate tod_set(ts); 159*0Sstevel@tonic-gate mutex_exit(&tod_lock); 160*0Sstevel@tonic-gate } 161*0Sstevel@tonic-gate break; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate /* Give some timezone playing room */ 164*0Sstevel@tonic-gate #define ONEWEEK (7 * 24 * 60 * 60) 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate case SGMTL: 167*0Sstevel@tonic-gate /* 168*0Sstevel@tonic-gate * Called from 32 bit land, negative values 169*0Sstevel@tonic-gate * are not sign extended, so we do that here 170*0Sstevel@tonic-gate * by casting it to an int and back. We also 171*0Sstevel@tonic-gate * clamp the value to within reason and detect 172*0Sstevel@tonic-gate * when a 64 bit call overflows an int. 173*0Sstevel@tonic-gate */ 174*0Sstevel@tonic-gate if ((error = secpolicy_settime(CRED())) == 0) { 175*0Sstevel@tonic-gate int newlag = (int)arg1; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 178*0Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE && 179*0Sstevel@tonic-gate (long)newlag != (long)arg1) { 180*0Sstevel@tonic-gate error = EOVERFLOW; 181*0Sstevel@tonic-gate } else 182*0Sstevel@tonic-gate #endif 183*0Sstevel@tonic-gate if (newlag >= -ONEWEEK && newlag <= ONEWEEK) 184*0Sstevel@tonic-gate sgmtl(newlag); 185*0Sstevel@tonic-gate else 186*0Sstevel@tonic-gate error = EOVERFLOW; 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate break; 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate case GGMTL: 191*0Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 192*0Sstevel@tonic-gate if (sulword((void *)arg1, ggmtl()) == -1) 193*0Sstevel@tonic-gate error = EFAULT; 194*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 195*0Sstevel@tonic-gate } else { 196*0Sstevel@tonic-gate time_t gmtl; 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate if ((gmtl = ggmtl()) > INT32_MAX) { 199*0Sstevel@tonic-gate /* 200*0Sstevel@tonic-gate * Since gmt_lag can at most be 201*0Sstevel@tonic-gate * +/- 12 hours, something is 202*0Sstevel@tonic-gate * *seriously* messed up here. 203*0Sstevel@tonic-gate */ 204*0Sstevel@tonic-gate error = EOVERFLOW; 205*0Sstevel@tonic-gate } else if (suword32((void *)arg1, (int32_t)gmtl) == -1) 206*0Sstevel@tonic-gate error = EFAULT; 207*0Sstevel@tonic-gate #endif 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate break; 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate case RTCSYNC: 212*0Sstevel@tonic-gate if ((error = secpolicy_settime(CRED())) == 0) 213*0Sstevel@tonic-gate rtcsync(); 214*0Sstevel@tonic-gate break; 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /* END OF real time clock management commands */ 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate default: 219*0Sstevel@tonic-gate error = EINVAL; 220*0Sstevel@tonic-gate break; 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate return (error == 0 ? 0 : set_errno(error)); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate void 226*0Sstevel@tonic-gate usd_to_ssd(user_desc_t *usd, struct ssd *ssd, selector_t sel) 227*0Sstevel@tonic-gate { 228*0Sstevel@tonic-gate ssd->bo = USEGD_GETBASE(usd); 229*0Sstevel@tonic-gate ssd->ls = USEGD_GETLIMIT(usd); 230*0Sstevel@tonic-gate ssd->sel = sel; 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate /* 233*0Sstevel@tonic-gate * set type, dpl and present bits. 234*0Sstevel@tonic-gate */ 235*0Sstevel@tonic-gate ssd->acc1 = usd->usd_type; 236*0Sstevel@tonic-gate ssd->acc1 |= usd->usd_dpl << 5; 237*0Sstevel@tonic-gate ssd->acc1 |= usd->usd_p << (5 + 2); 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate /* 240*0Sstevel@tonic-gate * set avl, DB and granularity bits. 241*0Sstevel@tonic-gate */ 242*0Sstevel@tonic-gate ssd->acc2 = usd->usd_avl; 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate #if defined(__amd64) 245*0Sstevel@tonic-gate ssd->acc2 |= usd->usd_long << 1; 246*0Sstevel@tonic-gate #else 247*0Sstevel@tonic-gate ssd->acc2 |= usd->usd_reserved << 1; 248*0Sstevel@tonic-gate #endif 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate ssd->acc2 |= usd->usd_def32 << (1 + 1); 251*0Sstevel@tonic-gate ssd->acc2 |= usd->usd_gran << (1 + 1 + 1); 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate static void 255*0Sstevel@tonic-gate ssd_to_usd(struct ssd *ssd, user_desc_t *usd) 256*0Sstevel@tonic-gate { 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate USEGD_SETBASE(usd, ssd->bo); 259*0Sstevel@tonic-gate USEGD_SETLIMIT(usd, ssd->ls); 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate /* 262*0Sstevel@tonic-gate * set type, dpl and present bits. 263*0Sstevel@tonic-gate */ 264*0Sstevel@tonic-gate usd->usd_type = ssd->acc1; 265*0Sstevel@tonic-gate usd->usd_dpl = ssd->acc1 >> 5; 266*0Sstevel@tonic-gate usd->usd_p = ssd->acc1 >> (5 + 2); 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate ASSERT(usd->usd_type >= SDT_MEMRO); 269*0Sstevel@tonic-gate ASSERT(usd->usd_dpl == SEL_UPL); 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate /* 272*0Sstevel@tonic-gate * set avl, DB and granularity bits. 273*0Sstevel@tonic-gate */ 274*0Sstevel@tonic-gate usd->usd_avl = ssd->acc2; 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate #if defined(__amd64) 277*0Sstevel@tonic-gate usd->usd_long = ssd->acc2 >> 1; 278*0Sstevel@tonic-gate #else 279*0Sstevel@tonic-gate usd->usd_reserved = ssd->acc2 >> 1; 280*0Sstevel@tonic-gate #endif 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate usd->usd_def32 = ssd->acc2 >> (1 + 1); 283*0Sstevel@tonic-gate usd->usd_gran = ssd->acc2 >> (1 + 1 + 1); 284*0Sstevel@tonic-gate } 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate static void 287*0Sstevel@tonic-gate ssd_to_sgd(struct ssd *ssd, gate_desc_t *sgd) 288*0Sstevel@tonic-gate { 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate sgd->sgd_looffset = ssd->bo; 291*0Sstevel@tonic-gate sgd->sgd_hioffset = ssd->bo >> 16; 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate sgd->sgd_selector = ssd->ls; 294*0Sstevel@tonic-gate /* 295*0Sstevel@tonic-gate * set type, dpl and present bits. 296*0Sstevel@tonic-gate */ 297*0Sstevel@tonic-gate sgd->sgd_type = ssd->acc1; 298*0Sstevel@tonic-gate sgd->sgd_dpl = ssd->acc1 >> 5; 299*0Sstevel@tonic-gate sgd->sgd_p = ssd->acc1 >> 7; 300*0Sstevel@tonic-gate ASSERT(sgd->sgd_type == SDT_SYSCGT); 301*0Sstevel@tonic-gate ASSERT(sgd->sgd_dpl == SEL_UPL); 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate #if defined(__i386) /* reserved, ignored in amd64 */ 304*0Sstevel@tonic-gate sgd->sgd_stkcpy = 0; 305*0Sstevel@tonic-gate #endif 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate static void ldt_installctx(kthread_t *, kthread_t *); 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate /*ARGSUSED*/ 311*0Sstevel@tonic-gate static void 312*0Sstevel@tonic-gate ldt_savectx(kthread_t *t) 313*0Sstevel@tonic-gate { 314*0Sstevel@tonic-gate #if defined(__amd64) 315*0Sstevel@tonic-gate /* 316*0Sstevel@tonic-gate * The 64-bit kernel must be sure to clear any stale ldt 317*0Sstevel@tonic-gate * selectors when context switching away from a process that 318*0Sstevel@tonic-gate * has a private ldt. Consider the following example: 319*0Sstevel@tonic-gate * 320*0Sstevel@tonic-gate * Wine creats a ldt descriptor and points a segment register 321*0Sstevel@tonic-gate * to it. 322*0Sstevel@tonic-gate * 323*0Sstevel@tonic-gate * We then context switch away from wine lwp to kernel 324*0Sstevel@tonic-gate * thread and hit breakpoint in kernel with kmdb 325*0Sstevel@tonic-gate * 326*0Sstevel@tonic-gate * When we continue and resume from kmdb we will #gp 327*0Sstevel@tonic-gate * fault since kmdb will have saved the stale ldt selector 328*0Sstevel@tonic-gate * from wine and will try to restore it but we are no longer in 329*0Sstevel@tonic-gate * the context of the wine process and do not have our 330*0Sstevel@tonic-gate * ldtr register pointing to the private ldt. 331*0Sstevel@tonic-gate */ 332*0Sstevel@tonic-gate clr_ldt_sregs(); 333*0Sstevel@tonic-gate #endif 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate cpu_fast_syscall_enable(NULL); 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate /* 339*0Sstevel@tonic-gate * When a thread with a private LDT execs, fast syscalls must be enabled for the 340*0Sstevel@tonic-gate * new process image. 341*0Sstevel@tonic-gate */ 342*0Sstevel@tonic-gate /* ARGSUSED */ 343*0Sstevel@tonic-gate static void 344*0Sstevel@tonic-gate ldt_freectx(kthread_t *t, int isexec) 345*0Sstevel@tonic-gate { 346*0Sstevel@tonic-gate if (isexec) { 347*0Sstevel@tonic-gate kpreempt_disable(); 348*0Sstevel@tonic-gate cpu_fast_syscall_enable(NULL); 349*0Sstevel@tonic-gate kpreempt_enable(); 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate } 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate /* 354*0Sstevel@tonic-gate * Install ctx op that ensures syscall/sysenter are disabled. 355*0Sstevel@tonic-gate * See comments below. 356*0Sstevel@tonic-gate * 357*0Sstevel@tonic-gate * When a thread with a private LDT creates a new LWP or forks, the new LWP 358*0Sstevel@tonic-gate * must have the LDT context ops installed. 359*0Sstevel@tonic-gate */ 360*0Sstevel@tonic-gate /* ARGSUSED */ 361*0Sstevel@tonic-gate static void 362*0Sstevel@tonic-gate ldt_installctx(kthread_t *t, kthread_t *ct) 363*0Sstevel@tonic-gate { 364*0Sstevel@tonic-gate kthread_t *targ = t; 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate /* 367*0Sstevel@tonic-gate * If this is a fork or an lwp_create, operate on the child thread. 368*0Sstevel@tonic-gate */ 369*0Sstevel@tonic-gate if (ct != NULL) 370*0Sstevel@tonic-gate targ = ct; 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate ASSERT(removectx(targ, NULL, ldt_savectx, cpu_fast_syscall_disable, 373*0Sstevel@tonic-gate ldt_installctx, ldt_installctx, cpu_fast_syscall_enable, 374*0Sstevel@tonic-gate ldt_freectx) == 0); 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate installctx(targ, NULL, ldt_savectx, cpu_fast_syscall_disable, 377*0Sstevel@tonic-gate ldt_installctx, ldt_installctx, cpu_fast_syscall_enable, 378*0Sstevel@tonic-gate ldt_freectx); 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate /* 381*0Sstevel@tonic-gate * We've just disabled fast system call and return instructions; take 382*0Sstevel@tonic-gate * the slow path out to make sure we don't try to use one to return 383*0Sstevel@tonic-gate * back to user. 384*0Sstevel@tonic-gate */ 385*0Sstevel@tonic-gate targ->t_post_sys = 1; 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate static int 389*0Sstevel@tonic-gate setdscr(caddr_t ap) 390*0Sstevel@tonic-gate { 391*0Sstevel@tonic-gate struct ssd ssd; /* request structure buffer */ 392*0Sstevel@tonic-gate ushort_t seli; /* selector index */ 393*0Sstevel@tonic-gate user_desc_t *dscrp; /* descriptor pointer */ 394*0Sstevel@tonic-gate proc_t *pp = ttoproc(curthread); 395*0Sstevel@tonic-gate kthread_t *t; 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_LP64) 398*0Sstevel@tonic-gate return (EINVAL); 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate if (copyin(ap, &ssd, sizeof (ssd)) < 0) 401*0Sstevel@tonic-gate return (EFAULT); 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate /* 404*0Sstevel@tonic-gate * LDT segments: executable and data at DPL 3 only. 405*0Sstevel@tonic-gate */ 406*0Sstevel@tonic-gate if (!SELISLDT(ssd.sel) || !SELISUPL(ssd.sel)) 407*0Sstevel@tonic-gate return (EINVAL); 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate /* 410*0Sstevel@tonic-gate * check the selector index. 411*0Sstevel@tonic-gate */ 412*0Sstevel@tonic-gate seli = SELTOIDX(ssd.sel); 413*0Sstevel@tonic-gate if (seli >= MAXNLDT || seli <= LDT_UDBASE) 414*0Sstevel@tonic-gate return (EINVAL); 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate mutex_enter(&pp->p_ldtlock); 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate /* 419*0Sstevel@tonic-gate * If this is the first time for this process then setup a 420*0Sstevel@tonic-gate * private LDT for it. 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate if (pp->p_ldt == NULL) { 423*0Sstevel@tonic-gate if (setup_ldt(pp) == NULL) { 424*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 425*0Sstevel@tonic-gate return (ENOMEM); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* 429*0Sstevel@tonic-gate * Now that this process has a private LDT, the use of 430*0Sstevel@tonic-gate * the syscall/sysret and sysenter/sysexit instructions 431*0Sstevel@tonic-gate * is forbidden for this processes because they destroy 432*0Sstevel@tonic-gate * the contents of %cs and %ss segment registers. 433*0Sstevel@tonic-gate * 434*0Sstevel@tonic-gate * Explicity disable them here and add context handlers 435*0Sstevel@tonic-gate * to all lwps in the process. Note that disabling 436*0Sstevel@tonic-gate * them here means we can't use sysret or sysexit on 437*0Sstevel@tonic-gate * the way out of this system call - so we force this 438*0Sstevel@tonic-gate * thread to take the slow path (which doesn't make use 439*0Sstevel@tonic-gate * of sysenter or sysexit) back out. 440*0Sstevel@tonic-gate */ 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate mutex_enter(&pp->p_lock); 443*0Sstevel@tonic-gate t = pp->p_tlist; 444*0Sstevel@tonic-gate do { 445*0Sstevel@tonic-gate ldt_installctx(t, NULL); 446*0Sstevel@tonic-gate } while ((t = t->t_forw) != pp->p_tlist); 447*0Sstevel@tonic-gate mutex_exit(&pp->p_lock); 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate kpreempt_disable(); 450*0Sstevel@tonic-gate cpu_fast_syscall_disable(NULL); 451*0Sstevel@tonic-gate kpreempt_enable(); 452*0Sstevel@tonic-gate ASSERT(curthread->t_post_sys != 0); 453*0Sstevel@tonic-gate wr_ldtr(ULDT_SEL); 454*0Sstevel@tonic-gate } 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate if (ldt_map(pp, seli) == NULL) { 457*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 458*0Sstevel@tonic-gate return (ENOMEM); 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate ASSERT(seli <= pp->p_ldtlimit); 462*0Sstevel@tonic-gate dscrp = &pp->p_ldt[seli]; 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate /* 465*0Sstevel@tonic-gate * On the 64-bit kernel, this is where things get more subtle. 466*0Sstevel@tonic-gate * Recall that in the 64-bit kernel, when we enter the kernel we 467*0Sstevel@tonic-gate * deliberately -don't- reload the segment selectors we came in on 468*0Sstevel@tonic-gate * for %ds, %es, %fs or %gs. Messing with selectors is expensive, 469*0Sstevel@tonic-gate * and the underlying descriptors are essentially ignored by the 470*0Sstevel@tonic-gate * hardware in long mode - except for the base that we override with 471*0Sstevel@tonic-gate * the gsbase MSRs. 472*0Sstevel@tonic-gate * 473*0Sstevel@tonic-gate * However, there's one unfortunate issue with this rosy picture -- 474*0Sstevel@tonic-gate * a descriptor that's not marked as 'present' will still generate 475*0Sstevel@tonic-gate * an #np when loading a segment register. 476*0Sstevel@tonic-gate * 477*0Sstevel@tonic-gate * Consider this case. An lwp creates a harmless LDT entry, points 478*0Sstevel@tonic-gate * one of it's segment registers at it, then tells the kernel (here) 479*0Sstevel@tonic-gate * to delete it. In the 32-bit kernel, the #np will happen on the 480*0Sstevel@tonic-gate * way back to userland where we reload the segment registers, and be 481*0Sstevel@tonic-gate * handled in kern_gpfault(). In the 64-bit kernel, the same thing 482*0Sstevel@tonic-gate * will happen in the normal case too. However, if we're trying to 483*0Sstevel@tonic-gate * use a debugger that wants to save and restore the segment registers, 484*0Sstevel@tonic-gate * and the debugger things that we have valid segment registers, we 485*0Sstevel@tonic-gate * have the problem that the debugger will try and restore the 486*0Sstevel@tonic-gate * segment register that points at the now 'not present' descriptor 487*0Sstevel@tonic-gate * and will take a #np right there. 488*0Sstevel@tonic-gate * 489*0Sstevel@tonic-gate * We should obviously fix the debugger to be paranoid about 490*0Sstevel@tonic-gate * -not- restoring segment registers that point to bad descriptors; 491*0Sstevel@tonic-gate * however we can prevent the problem here if we check to see if any 492*0Sstevel@tonic-gate * of the segment registers are still pointing at the thing we're 493*0Sstevel@tonic-gate * destroying; if they are, return an error instead. (That also seems 494*0Sstevel@tonic-gate * a lot better failure mode than SIGKILL and a core file 495*0Sstevel@tonic-gate * from kern_gpfault() too.) 496*0Sstevel@tonic-gate */ 497*0Sstevel@tonic-gate if (SI86SSD_PRES(&ssd) == 0) { 498*0Sstevel@tonic-gate kthread_t *t; 499*0Sstevel@tonic-gate int bad = 0; 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate /* 502*0Sstevel@tonic-gate * Look carefully at the segment registers of every lwp 503*0Sstevel@tonic-gate * in the process (they're all stopped by our caller). 504*0Sstevel@tonic-gate * If we're about to invalidate a descriptor that's still 505*0Sstevel@tonic-gate * being referenced by *any* of them, return an error, 506*0Sstevel@tonic-gate * rather than having them #gp on their way out of the kernel. 507*0Sstevel@tonic-gate */ 508*0Sstevel@tonic-gate ASSERT(pp->p_lwprcnt == 1); 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate mutex_enter(&pp->p_lock); 511*0Sstevel@tonic-gate t = pp->p_tlist; 512*0Sstevel@tonic-gate do { 513*0Sstevel@tonic-gate klwp_t *lwp = ttolwp(t); 514*0Sstevel@tonic-gate struct regs *rp = lwp->lwp_regs; 515*0Sstevel@tonic-gate #if defined(__amd64) 516*0Sstevel@tonic-gate pcb_t *pcb = &lwp->lwp_pcb; 517*0Sstevel@tonic-gate #endif 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate if (ssd.sel == rp->r_cs || ssd.sel == rp->r_ss) { 520*0Sstevel@tonic-gate bad = 1; 521*0Sstevel@tonic-gate break; 522*0Sstevel@tonic-gate } 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate #if defined(__amd64) 525*0Sstevel@tonic-gate if (pcb->pcb_flags & RUPDATE_PENDING) { 526*0Sstevel@tonic-gate if (ssd.sel == pcb->pcb_ds || 527*0Sstevel@tonic-gate ssd.sel == pcb->pcb_es || 528*0Sstevel@tonic-gate ssd.sel == pcb->pcb_fs || 529*0Sstevel@tonic-gate ssd.sel == pcb->pcb_gs) { 530*0Sstevel@tonic-gate bad = 1; 531*0Sstevel@tonic-gate break; 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate } else 534*0Sstevel@tonic-gate #endif 535*0Sstevel@tonic-gate { 536*0Sstevel@tonic-gate if (ssd.sel == rp->r_ds || 537*0Sstevel@tonic-gate ssd.sel == rp->r_es || 538*0Sstevel@tonic-gate ssd.sel == rp->r_fs || 539*0Sstevel@tonic-gate ssd.sel == rp->r_gs) { 540*0Sstevel@tonic-gate bad = 1; 541*0Sstevel@tonic-gate break; 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate } while ((t = t->t_forw) != pp->p_tlist); 546*0Sstevel@tonic-gate mutex_exit(&pp->p_lock); 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate if (bad) { 549*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 550*0Sstevel@tonic-gate return (EBUSY); 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate } 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate /* 555*0Sstevel@tonic-gate * If acc1 is zero, clear the descriptor (including the 'present' bit) 556*0Sstevel@tonic-gate */ 557*0Sstevel@tonic-gate if (ssd.acc1 == 0) { 558*0Sstevel@tonic-gate bzero(dscrp, sizeof (*dscrp)); 559*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 560*0Sstevel@tonic-gate return (0); 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate /* 564*0Sstevel@tonic-gate * Check segment type, allow segment not present and 565*0Sstevel@tonic-gate * only user DPL (3). 566*0Sstevel@tonic-gate */ 567*0Sstevel@tonic-gate if (SI86SSD_DPL(&ssd) != SEL_UPL) { 568*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 569*0Sstevel@tonic-gate return (EINVAL); 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate #if defined(__amd64) 573*0Sstevel@tonic-gate /* 574*0Sstevel@tonic-gate * Do not allow 32-bit applications to create 64-bit mode code segments. 575*0Sstevel@tonic-gate */ 576*0Sstevel@tonic-gate if (SI86SSD_ISUSEG(&ssd) && ((SI86SSD_TYPE(&ssd) >> 3) & 1) == 1 && 577*0Sstevel@tonic-gate SI86SSD_ISLONG(&ssd)) { 578*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 579*0Sstevel@tonic-gate return (EINVAL); 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate #endif /* __amd64 */ 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate /* 584*0Sstevel@tonic-gate * Set up a code or data user segment descriptor. 585*0Sstevel@tonic-gate */ 586*0Sstevel@tonic-gate if (SI86SSD_ISUSEG(&ssd)) { 587*0Sstevel@tonic-gate ssd_to_usd(&ssd, dscrp); 588*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 589*0Sstevel@tonic-gate return (0); 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate /* 593*0Sstevel@tonic-gate * Allow a call gate only if the destination is in the LDT. 594*0Sstevel@tonic-gate */ 595*0Sstevel@tonic-gate if (SI86SSD_TYPE(&ssd) == SDT_SYSCGT && SELISLDT(ssd.ls)) { 596*0Sstevel@tonic-gate ssd_to_sgd(&ssd, (gate_desc_t *)dscrp); 597*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 598*0Sstevel@tonic-gate return (0); 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 602*0Sstevel@tonic-gate return (EINVAL); 603*0Sstevel@tonic-gate } 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate /* 606*0Sstevel@tonic-gate * Allocate a private LDT for this process and initialize it with the 607*0Sstevel@tonic-gate * default entries. Returns 0 for errors, pointer to LDT for success. 608*0Sstevel@tonic-gate */ 609*0Sstevel@tonic-gate static void * 610*0Sstevel@tonic-gate setup_ldt(proc_t *pp) 611*0Sstevel@tonic-gate { 612*0Sstevel@tonic-gate user_desc_t *ldtp; /* descriptor pointer */ 613*0Sstevel@tonic-gate pgcnt_t npages = btopr(MAXNLDT * sizeof (user_desc_t)); 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate /* 616*0Sstevel@tonic-gate * Allocate maximum virtual space we need for this LDT. 617*0Sstevel@tonic-gate */ 618*0Sstevel@tonic-gate ldtp = vmem_alloc(heap_arena, ptob(npages), VM_SLEEP); 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate /* 621*0Sstevel@tonic-gate * Allocate the minimum number of physical pages for LDT. 622*0Sstevel@tonic-gate */ 623*0Sstevel@tonic-gate if (segkmem_xalloc(NULL, ldtp, MINNLDT * sizeof (user_desc_t), 624*0Sstevel@tonic-gate VM_SLEEP, 0, segkmem_page_create, NULL) == NULL) { 625*0Sstevel@tonic-gate vmem_free(heap_arena, ldtp, ptob(npages)); 626*0Sstevel@tonic-gate return (0); 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate bzero(ldtp, ptob(btopr(MINNLDT * sizeof (user_desc_t)))); 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate /* 631*0Sstevel@tonic-gate * Copy the default LDT entries into the new table. 632*0Sstevel@tonic-gate */ 633*0Sstevel@tonic-gate bcopy(ldt0_default, ldtp, MINNLDT * sizeof (user_desc_t)); 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate kpreempt_disable(); 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate /* Update proc structure. XXX - need any locks here??? */ 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate set_syssegd(&pp->p_ldt_desc, ldtp, MINNLDT * sizeof (user_desc_t) - 1, 640*0Sstevel@tonic-gate SDT_SYSLDT, SEL_KPL); 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate pp->p_ldtlimit = MINNLDT - 1; 643*0Sstevel@tonic-gate pp->p_ldt = ldtp; 644*0Sstevel@tonic-gate if (pp == curproc) 645*0Sstevel@tonic-gate *((system_desc_t *)&CPU->cpu_gdt[GDT_LDT]) = pp->p_ldt_desc; 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate kpreempt_enable(); 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate return (ldtp); 650*0Sstevel@tonic-gate } 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate /* 653*0Sstevel@tonic-gate * Load LDT register with the current process's LDT. 654*0Sstevel@tonic-gate */ 655*0Sstevel@tonic-gate void 656*0Sstevel@tonic-gate ldt_load(void) 657*0Sstevel@tonic-gate { 658*0Sstevel@tonic-gate proc_t *p = curthread->t_procp; 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate ASSERT(curthread->t_preempt != 0); 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate *((system_desc_t *)&CPU->cpu_gdt[GDT_LDT]) = p->p_ldt_desc; 663*0Sstevel@tonic-gate wr_ldtr(ULDT_SEL); 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate /* 667*0Sstevel@tonic-gate * Map the page corresponding to the selector entry. If the page is 668*0Sstevel@tonic-gate * already mapped then it simply returns with the pointer to the entry. 669*0Sstevel@tonic-gate * Otherwise it allocates a physical page for it and returns the pointer 670*0Sstevel@tonic-gate * to the entry. Returns 0 for errors. 671*0Sstevel@tonic-gate */ 672*0Sstevel@tonic-gate static void * 673*0Sstevel@tonic-gate ldt_map(proc_t *pp, uint_t seli) 674*0Sstevel@tonic-gate { 675*0Sstevel@tonic-gate caddr_t ent0_addr = (caddr_t)&pp->p_ldt[0]; 676*0Sstevel@tonic-gate caddr_t ent_addr = (caddr_t)&pp->p_ldt[seli]; 677*0Sstevel@tonic-gate volatile caddr_t page = (caddr_t)((uintptr_t)ent0_addr & (~PAGEOFFSET)); 678*0Sstevel@tonic-gate caddr_t epage = (caddr_t)((uintptr_t)ent_addr & (~PAGEOFFSET)); 679*0Sstevel@tonic-gate on_trap_data_t otd; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate ASSERT(pp->p_ldt != NULL); 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate if (seli <= pp->p_ldtlimit) 684*0Sstevel@tonic-gate return (ent_addr); 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate /* 687*0Sstevel@tonic-gate * We are increasing the size of the process's LDT. 688*0Sstevel@tonic-gate * Make sure this and all intervening pages are mapped. 689*0Sstevel@tonic-gate */ 690*0Sstevel@tonic-gate while (page <= epage) { 691*0Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) 692*0Sstevel@tonic-gate (void) *(volatile int *)page; /* peek at the page */ 693*0Sstevel@tonic-gate else { /* Allocate a physical page */ 694*0Sstevel@tonic-gate if (segkmem_xalloc(NULL, page, PAGESIZE, VM_SLEEP, 0, 695*0Sstevel@tonic-gate segkmem_page_create, NULL) == NULL) { 696*0Sstevel@tonic-gate no_trap(); 697*0Sstevel@tonic-gate return (NULL); 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate bzero(page, PAGESIZE); 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate no_trap(); 702*0Sstevel@tonic-gate page += PAGESIZE; 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate /* XXX - need any locks to update proc_t or gdt ??? */ 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate ASSERT(curproc == pp); 708*0Sstevel@tonic-gate 709*0Sstevel@tonic-gate kpreempt_disable(); 710*0Sstevel@tonic-gate pp->p_ldtlimit = seli; 711*0Sstevel@tonic-gate SYSSEGD_SETLIMIT(&pp->p_ldt_desc, (seli+1) * sizeof (user_desc_t) -1); 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate ldt_load(); 714*0Sstevel@tonic-gate kpreempt_enable(); 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate return (ent_addr); 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate /* 720*0Sstevel@tonic-gate * Free up the kernel memory used for LDT of this process. 721*0Sstevel@tonic-gate */ 722*0Sstevel@tonic-gate void 723*0Sstevel@tonic-gate ldt_free(proc_t *pp) 724*0Sstevel@tonic-gate { 725*0Sstevel@tonic-gate on_trap_data_t otd; 726*0Sstevel@tonic-gate caddr_t start, end; 727*0Sstevel@tonic-gate volatile caddr_t addr; 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate ASSERT(pp->p_ldt != NULL); 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate mutex_enter(&pp->p_ldtlock); 732*0Sstevel@tonic-gate start = (caddr_t)pp->p_ldt; /* beginning of the LDT */ 733*0Sstevel@tonic-gate end = start + (pp->p_ldtlimit * sizeof (user_desc_t)); 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate /* Free the physical page(s) used for mapping LDT */ 736*0Sstevel@tonic-gate for (addr = start; addr <= end; addr += PAGESIZE) { 737*0Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 738*0Sstevel@tonic-gate /* peek at the address */ 739*0Sstevel@tonic-gate (void) *(volatile int *)addr; 740*0Sstevel@tonic-gate segkmem_free(NULL, addr, PAGESIZE); 741*0Sstevel@tonic-gate } 742*0Sstevel@tonic-gate } 743*0Sstevel@tonic-gate no_trap(); 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate /* Free up the virtual address space used for this LDT */ 746*0Sstevel@tonic-gate vmem_free(heap_arena, pp->p_ldt, 747*0Sstevel@tonic-gate ptob(btopr(MAXNLDT * sizeof (user_desc_t)))); 748*0Sstevel@tonic-gate kpreempt_disable(); 749*0Sstevel@tonic-gate pp->p_ldt = NULL; 750*0Sstevel@tonic-gate pp->p_ldt_desc = ldt0_default_desc; 751*0Sstevel@tonic-gate if (pp == curproc) 752*0Sstevel@tonic-gate ldt_load(); 753*0Sstevel@tonic-gate kpreempt_enable(); 754*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 755*0Sstevel@tonic-gate } 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate /* 758*0Sstevel@tonic-gate * On fork copy new ldt for child. 759*0Sstevel@tonic-gate */ 760*0Sstevel@tonic-gate int 761*0Sstevel@tonic-gate ldt_dup(proc_t *pp, proc_t *cp) 762*0Sstevel@tonic-gate { 763*0Sstevel@tonic-gate on_trap_data_t otd; 764*0Sstevel@tonic-gate caddr_t start, end; 765*0Sstevel@tonic-gate volatile caddr_t addr, caddr; 766*0Sstevel@tonic-gate int minsize; 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate if (pp->p_ldt == NULL) { 769*0Sstevel@tonic-gate cp->p_ldt_desc = ldt0_default_desc; 770*0Sstevel@tonic-gate return (0); 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate if (setup_ldt(cp) == NULL) { 774*0Sstevel@tonic-gate return (ENOMEM); 775*0Sstevel@tonic-gate } 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate mutex_enter(&pp->p_ldtlock); 778*0Sstevel@tonic-gate cp->p_ldtlimit = pp->p_ldtlimit; 779*0Sstevel@tonic-gate SYSSEGD_SETLIMIT(&cp->p_ldt_desc, 780*0Sstevel@tonic-gate (pp->p_ldtlimit+1) * sizeof (user_desc_t) -1); 781*0Sstevel@tonic-gate start = (caddr_t)pp->p_ldt; /* beginning of the LDT */ 782*0Sstevel@tonic-gate end = start + (pp->p_ldtlimit * sizeof (user_desc_t)); 783*0Sstevel@tonic-gate caddr = (caddr_t)cp->p_ldt; /* child LDT start */ 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate minsize = ((MINNLDT * sizeof (user_desc_t)) + PAGESIZE) & ~PAGEOFFSET; 786*0Sstevel@tonic-gate /* Walk thru the physical page(s) used for parent's LDT */ 787*0Sstevel@tonic-gate for (addr = start; addr <= end; addr += PAGESIZE, caddr += PAGESIZE) { 788*0Sstevel@tonic-gate if (!on_trap(&otd, OT_DATA_ACCESS)) { 789*0Sstevel@tonic-gate (void) *(volatile int *)addr; /* peek at the address */ 790*0Sstevel@tonic-gate /* allocate a page if necessary */ 791*0Sstevel@tonic-gate if (caddr >= ((caddr_t)cp->p_ldt + minsize)) { 792*0Sstevel@tonic-gate if (segkmem_xalloc(NULL, caddr, PAGESIZE, 793*0Sstevel@tonic-gate VM_SLEEP, 0, segkmem_page_create, NULL) == 794*0Sstevel@tonic-gate NULL) { 795*0Sstevel@tonic-gate no_trap(); 796*0Sstevel@tonic-gate ldt_free(cp); 797*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 798*0Sstevel@tonic-gate return (ENOMEM); 799*0Sstevel@tonic-gate } 800*0Sstevel@tonic-gate } 801*0Sstevel@tonic-gate bcopy(addr, caddr, PAGESIZE); 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate } 804*0Sstevel@tonic-gate no_trap(); 805*0Sstevel@tonic-gate mutex_exit(&pp->p_ldtlock); 806*0Sstevel@tonic-gate return (0); 807*0Sstevel@tonic-gate } 808