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