xref: /titanic_51/usr/src/uts/intel/ia32/syscall/getcontext.c (revision 8f798d3afbe38d59cc0a708261dbb729f1b6b209)
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
58efd794bSsudheer  * Common Development and Distribution License (the "License").
68efd794bSsudheer  * 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 
227c478bd9Sstevel@tonic-gate /*
23bdf0047cSRoger A. Faulkner  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277be238fcSRoger A. Faulkner /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287be238fcSRoger A. Faulkner /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/param.h>
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/vmparam.h>
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/signal.h>
357c478bd9Sstevel@tonic-gate #include <sys/stack.h>
367c478bd9Sstevel@tonic-gate #include <sys/regset.h>
377c478bd9Sstevel@tonic-gate #include <sys/privregs.h>
387c478bd9Sstevel@tonic-gate #include <sys/frame.h>
397c478bd9Sstevel@tonic-gate #include <sys/proc.h>
40*8f798d3aSRoger A. Faulkner #include <sys/brand.h>
417c478bd9Sstevel@tonic-gate #include <sys/psw.h>
427c478bd9Sstevel@tonic-gate #include <sys/ucontext.h>
437c478bd9Sstevel@tonic-gate #include <sys/asm_linkage.h>
447c478bd9Sstevel@tonic-gate #include <sys/errno.h>
457c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
467c478bd9Sstevel@tonic-gate #include <sys/schedctl.h>
477c478bd9Sstevel@tonic-gate #include <sys/debug.h>
487c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Save user context.
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate void
54bdf0047cSRoger A. Faulkner savecontext(ucontext_t *ucp, const k_sigset_t *mask)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
577c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
588efd794bSsudheer 	struct regs *rp = lwptoregs(lwp);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	/*
617c478bd9Sstevel@tonic-gate 	 * We unconditionally assign to every field through the end
627c478bd9Sstevel@tonic-gate 	 * of the gregs, but we need to bzero() everything -after- that
637c478bd9Sstevel@tonic-gate 	 * to avoid having any kernel stack garbage escape to userland.
647c478bd9Sstevel@tonic-gate 	 */
657c478bd9Sstevel@tonic-gate 	bzero(&ucp->uc_mcontext.fpregs, sizeof (ucontext_t) -
667c478bd9Sstevel@tonic-gate 	    offsetof(ucontext_t, uc_mcontext.fpregs));
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	ucp->uc_flags = UC_ALL;
697c478bd9Sstevel@tonic-gate 	ucp->uc_link = (struct ucontext *)lwp->lwp_oldcontext;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	/*
727c478bd9Sstevel@tonic-gate 	 * Try to copyin() the ustack if one is registered. If the stack
737c478bd9Sstevel@tonic-gate 	 * has zero size, this indicates that stack bounds checking has
747c478bd9Sstevel@tonic-gate 	 * been disabled for this LWP. If stack bounds checking is disabled
757c478bd9Sstevel@tonic-gate 	 * or the copyin() fails, we fall back to the legacy behavior.
767c478bd9Sstevel@tonic-gate 	 */
777c478bd9Sstevel@tonic-gate 	if (lwp->lwp_ustack == NULL ||
787c478bd9Sstevel@tonic-gate 	    copyin((void *)lwp->lwp_ustack, &ucp->uc_stack,
797c478bd9Sstevel@tonic-gate 	    sizeof (ucp->uc_stack)) != 0 ||
807c478bd9Sstevel@tonic-gate 	    ucp->uc_stack.ss_size == 0) {
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 		if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) {
837c478bd9Sstevel@tonic-gate 			ucp->uc_stack = lwp->lwp_sigaltstack;
847c478bd9Sstevel@tonic-gate 		} else {
857c478bd9Sstevel@tonic-gate 			ucp->uc_stack.ss_sp = p->p_usrstack - p->p_stksize;
867c478bd9Sstevel@tonic-gate 			ucp->uc_stack.ss_size = p->p_stksize;
877c478bd9Sstevel@tonic-gate 			ucp->uc_stack.ss_flags = 0;
887c478bd9Sstevel@tonic-gate 		}
897c478bd9Sstevel@tonic-gate 	}
907c478bd9Sstevel@tonic-gate 
9186d5155bSksadhukh 	/*
9286d5155bSksadhukh 	 * If either the trace flag or REQUEST_STEP is set,
9386d5155bSksadhukh 	 * arrange for single-stepping and turn off the trace flag.
9486d5155bSksadhukh 	 */
9586d5155bSksadhukh 	if ((rp->r_ps & PS_T) || (lwp->lwp_pcb.pcb_flags & REQUEST_STEP)) {
9686d5155bSksadhukh 		/*
9786d5155bSksadhukh 		 * Clear PS_T so that saved user context won't have trace
9886d5155bSksadhukh 		 * flag set.
9986d5155bSksadhukh 		 */
10086d5155bSksadhukh 		rp->r_ps &= ~PS_T;
10186d5155bSksadhukh 
10286d5155bSksadhukh 		if (!(lwp->lwp_pcb.pcb_flags & REQUEST_NOSTEP)) {
10386d5155bSksadhukh 			lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
10486d5155bSksadhukh 			/*
10586d5155bSksadhukh 			 * trap() always checks DEBUG_PENDING before
10686d5155bSksadhukh 			 * checking for any pending signal. This at times
10786d5155bSksadhukh 			 * can potentially lead to DEBUG_PENDING not being
10886d5155bSksadhukh 			 * honoured. (for eg: the lwp is stopped by
10986d5155bSksadhukh 			 * stop_on_fault() called from trap(), after being
11086d5155bSksadhukh 			 * awakened it might see a pending signal and call
11186d5155bSksadhukh 			 * savecontext(), however on the way back to userland
11286d5155bSksadhukh 			 * there is no place it can be detected). Hence in
11386d5155bSksadhukh 			 * anticipation of such occassions, set AST flag for
11486d5155bSksadhukh 			 * the thread which will make the thread take an
11586d5155bSksadhukh 			 * excursion through trap() where it will be handled
11686d5155bSksadhukh 			 * appropriately.
11786d5155bSksadhukh 			 */
11886d5155bSksadhukh 			aston(curthread);
11986d5155bSksadhukh 		}
12086d5155bSksadhukh 	}
12186d5155bSksadhukh 
1227c478bd9Sstevel@tonic-gate 	getgregs(lwp, ucp->uc_mcontext.gregs);
1237c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN)
1247c478bd9Sstevel@tonic-gate 		getfpregs(lwp, &ucp->uc_mcontext.fpregs);
1257c478bd9Sstevel@tonic-gate 	else
1267c478bd9Sstevel@tonic-gate 		ucp->uc_flags &= ~UC_FPU;
1277c478bd9Sstevel@tonic-gate 
128bdf0047cSRoger A. Faulkner 	sigktou(mask, &ucp->uc_sigmask);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate  * Restore user context.
1337c478bd9Sstevel@tonic-gate  */
1347c478bd9Sstevel@tonic-gate void
1357c478bd9Sstevel@tonic-gate restorecontext(ucontext_t *ucp)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate 	kthread_t *t = curthread;
1387c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(t);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	lwp->lwp_oldcontext = (uintptr_t)ucp->uc_link;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	if (ucp->uc_flags & UC_STACK) {
1437c478bd9Sstevel@tonic-gate 		if (ucp->uc_stack.ss_flags == SS_ONSTACK)
1447c478bd9Sstevel@tonic-gate 			lwp->lwp_sigaltstack = ucp->uc_stack;
1457c478bd9Sstevel@tonic-gate 		else
1467c478bd9Sstevel@tonic-gate 			lwp->lwp_sigaltstack.ss_flags &= ~SS_ONSTACK;
1477c478bd9Sstevel@tonic-gate 	}
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	if (ucp->uc_flags & UC_CPU) {
1508efd794bSsudheer 		/*
1518efd794bSsudheer 		 * If the trace flag is set, mark the lwp to take a
1528efd794bSsudheer 		 * single-step trap on return to user level (below).
1538efd794bSsudheer 		 * The x86 lcall interface and sysenter has already done this,
1548efd794bSsudheer 		 * and turned off the flag, but amd64 syscall interface has not.
1558efd794bSsudheer 		 */
1568efd794bSsudheer 		if (lwptoregs(lwp)->r_ps & PS_T)
1578efd794bSsudheer 			lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
1587c478bd9Sstevel@tonic-gate 		setgregs(lwp, ucp->uc_mcontext.gregs);
1597c478bd9Sstevel@tonic-gate 		lwp->lwp_eosys = JUSTRETURN;
1607c478bd9Sstevel@tonic-gate 		t->t_post_sys = 1;
161d8aa0f5aSsudheer 		aston(curthread);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	if (ucp->uc_flags & UC_FPU)
1657c478bd9Sstevel@tonic-gate 		setfpregs(lwp, &ucp->uc_mcontext.fpregs);
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	if (ucp->uc_flags & UC_SIGMASK) {
1687be238fcSRoger A. Faulkner 		/*
1697be238fcSRoger A. Faulkner 		 * We don't need to acquire p->p_lock here;
1707be238fcSRoger A. Faulkner 		 * we are manipulating thread-private data.
1717be238fcSRoger A. Faulkner 		 */
1727c478bd9Sstevel@tonic-gate 		schedctl_finish_sigblock(t);
1737c478bd9Sstevel@tonic-gate 		sigutok(&ucp->uc_sigmask, &t->t_hold);
1747be238fcSRoger A. Faulkner 		if (sigcheck(ttoproc(t), t))
1757c478bd9Sstevel@tonic-gate 			t->t_sig_check = 1;
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate int
1817c478bd9Sstevel@tonic-gate getsetcontext(int flag, void *arg)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 	ucontext_t uc;
1847c478bd9Sstevel@tonic-gate 	ucontext_t *ucp;
1857c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
1867c478bd9Sstevel@tonic-gate 	stack_t dummy_stk;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	/*
1897c478bd9Sstevel@tonic-gate 	 * In future releases, when the ucontext structure grows,
1907c478bd9Sstevel@tonic-gate 	 * getcontext should be modified to only return the fields
1917c478bd9Sstevel@tonic-gate 	 * specified in the uc_flags.  That way, the structure can grow
1927c478bd9Sstevel@tonic-gate 	 * and still be binary compatible will all .o's which will only
1937c478bd9Sstevel@tonic-gate 	 * have old fields defined in uc_flags
1947c478bd9Sstevel@tonic-gate 	 */
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	switch (flag) {
1977c478bd9Sstevel@tonic-gate 	default:
1987c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	case GETCONTEXT:
2017c478bd9Sstevel@tonic-gate 		schedctl_finish_sigblock(curthread);
202bdf0047cSRoger A. Faulkner 		savecontext(&uc, &curthread->t_hold);
203*8f798d3aSRoger A. Faulkner 		if (uc.uc_flags & UC_SIGMASK)
204*8f798d3aSRoger A. Faulkner 			SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
2057c478bd9Sstevel@tonic-gate 		if (copyout(&uc, arg, sizeof (uc)))
2067c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
2077c478bd9Sstevel@tonic-gate 		return (0);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	case SETCONTEXT:
2107c478bd9Sstevel@tonic-gate 		ucp = arg;
2117c478bd9Sstevel@tonic-gate 		if (ucp == NULL)
2127c478bd9Sstevel@tonic-gate 			exit(CLD_EXITED, 0);
2137c478bd9Sstevel@tonic-gate 		/*
2147c478bd9Sstevel@tonic-gate 		 * Don't copyin filler or floating state unless we need it.
2157c478bd9Sstevel@tonic-gate 		 * The ucontext_t struct and fields are specified in the ABI.
2167c478bd9Sstevel@tonic-gate 		 */
2177c478bd9Sstevel@tonic-gate 		if (copyin(ucp, &uc, sizeof (ucontext_t) -
2187c478bd9Sstevel@tonic-gate 		    sizeof (uc.uc_filler) -
2197c478bd9Sstevel@tonic-gate 		    sizeof (uc.uc_mcontext.fpregs))) {
2207c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
2217c478bd9Sstevel@tonic-gate 		}
222*8f798d3aSRoger A. Faulkner 		if (uc.uc_flags & UC_SIGMASK)
223*8f798d3aSRoger A. Faulkner 			SIGSET_BRAND_TO_NATIVE(&uc.uc_sigmask);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		if ((uc.uc_flags & UC_FPU) &&
2267c478bd9Sstevel@tonic-gate 		    copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs,
2277c478bd9Sstevel@tonic-gate 		    sizeof (uc.uc_mcontext.fpregs))) {
2287c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
2297c478bd9Sstevel@tonic-gate 		}
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 		restorecontext(&uc);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 		if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0))
2347c478bd9Sstevel@tonic-gate 			(void) copyout(&uc.uc_stack, (stack_t *)lwp->lwp_ustack,
2357c478bd9Sstevel@tonic-gate 			    sizeof (uc.uc_stack));
2367c478bd9Sstevel@tonic-gate 		return (0);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	case GETUSTACK:
2397c478bd9Sstevel@tonic-gate 		if (copyout(&lwp->lwp_ustack, arg, sizeof (caddr_t)))
2407c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
2417c478bd9Sstevel@tonic-gate 		return (0);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	case SETUSTACK:
2447c478bd9Sstevel@tonic-gate 		if (copyin(arg, &dummy_stk, sizeof (dummy_stk)))
2457c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
2467c478bd9Sstevel@tonic-gate 		lwp->lwp_ustack = (uintptr_t)arg;
2477c478bd9Sstevel@tonic-gate 		return (0);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * Save user context for 32-bit processes.
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate void
257bdf0047cSRoger A. Faulkner savecontext32(ucontext32_t *ucp, const k_sigset_t *mask)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
2607c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
2618efd794bSsudheer 	struct regs *rp = lwptoregs(lwp);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	bzero(&ucp->uc_mcontext.fpregs, sizeof (ucontext32_t) -
2647c478bd9Sstevel@tonic-gate 	    offsetof(ucontext32_t, uc_mcontext.fpregs));
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	ucp->uc_flags = UC_ALL;
2677c478bd9Sstevel@tonic-gate 	ucp->uc_link = (caddr32_t)lwp->lwp_oldcontext;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	if (lwp->lwp_ustack == NULL ||
2707c478bd9Sstevel@tonic-gate 	    copyin((void *)lwp->lwp_ustack, &ucp->uc_stack,
2717c478bd9Sstevel@tonic-gate 	    sizeof (ucp->uc_stack)) != 0 ||
2727c478bd9Sstevel@tonic-gate 	    ucp->uc_stack.ss_size == 0) {
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 		if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) {
2757c478bd9Sstevel@tonic-gate 			ucp->uc_stack.ss_sp =
2767c478bd9Sstevel@tonic-gate 			    (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
2777c478bd9Sstevel@tonic-gate 			ucp->uc_stack.ss_size =
2787c478bd9Sstevel@tonic-gate 			    (size32_t)lwp->lwp_sigaltstack.ss_size;
2797c478bd9Sstevel@tonic-gate 			ucp->uc_stack.ss_flags = SS_ONSTACK;
2807c478bd9Sstevel@tonic-gate 		} else {
2817c478bd9Sstevel@tonic-gate 			ucp->uc_stack.ss_sp = (caddr32_t)(uintptr_t)
2827c478bd9Sstevel@tonic-gate 			    (p->p_usrstack - p->p_stksize);
2837c478bd9Sstevel@tonic-gate 			ucp->uc_stack.ss_size = (size32_t)p->p_stksize;
2847c478bd9Sstevel@tonic-gate 			ucp->uc_stack.ss_flags = 0;
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 
28886d5155bSksadhukh 	/*
28986d5155bSksadhukh 	 * If either the trace flag or REQUEST_STEP is set, arrange
29086d5155bSksadhukh 	 * for single-stepping and turn off the trace flag.
29186d5155bSksadhukh 	 */
29286d5155bSksadhukh 	if ((rp->r_ps & PS_T) || (lwp->lwp_pcb.pcb_flags & REQUEST_STEP)) {
29386d5155bSksadhukh 		/*
29486d5155bSksadhukh 		 * Clear PS_T so that saved user context won't have trace
29586d5155bSksadhukh 		 * flag set.
29686d5155bSksadhukh 		 */
29786d5155bSksadhukh 		rp->r_ps &= ~PS_T;
29886d5155bSksadhukh 
29986d5155bSksadhukh 		if (!(lwp->lwp_pcb.pcb_flags & REQUEST_NOSTEP)) {
30086d5155bSksadhukh 			lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
30186d5155bSksadhukh 			/*
30286d5155bSksadhukh 			 * See comments in savecontext().
30386d5155bSksadhukh 			 */
30486d5155bSksadhukh 			aston(curthread);
30586d5155bSksadhukh 		}
30686d5155bSksadhukh 	}
30786d5155bSksadhukh 
3087c478bd9Sstevel@tonic-gate 	getgregs32(lwp, ucp->uc_mcontext.gregs);
3097c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN)
3107c478bd9Sstevel@tonic-gate 		getfpregs32(lwp, &ucp->uc_mcontext.fpregs);
3117c478bd9Sstevel@tonic-gate 	else
3127c478bd9Sstevel@tonic-gate 		ucp->uc_flags &= ~UC_FPU;
3137c478bd9Sstevel@tonic-gate 
314bdf0047cSRoger A. Faulkner 	sigktou(mask, &ucp->uc_sigmask);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate int
3187c478bd9Sstevel@tonic-gate getsetcontext32(int flag, void *arg)
3197c478bd9Sstevel@tonic-gate {
3207c478bd9Sstevel@tonic-gate 	ucontext32_t uc;
3217c478bd9Sstevel@tonic-gate 	ucontext_t ucnat;
3227c478bd9Sstevel@tonic-gate 	ucontext32_t *ucp;
3237c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
3247c478bd9Sstevel@tonic-gate 	caddr32_t ustack32;
3257c478bd9Sstevel@tonic-gate 	stack32_t dummy_stk32;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	switch (flag) {
3287c478bd9Sstevel@tonic-gate 	default:
3297c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	case GETCONTEXT:
3327c478bd9Sstevel@tonic-gate 		schedctl_finish_sigblock(curthread);
333bdf0047cSRoger A. Faulkner 		savecontext32(&uc, &curthread->t_hold);
334*8f798d3aSRoger A. Faulkner 		if (uc.uc_flags & UC_SIGMASK)
335*8f798d3aSRoger A. Faulkner 			SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
3367c478bd9Sstevel@tonic-gate 		if (copyout(&uc, arg, sizeof (uc)))
3377c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
3387c478bd9Sstevel@tonic-gate 		return (0);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	case SETCONTEXT:
3417c478bd9Sstevel@tonic-gate 		ucp = arg;
3427c478bd9Sstevel@tonic-gate 		if (ucp == NULL)
3437c478bd9Sstevel@tonic-gate 			exit(CLD_EXITED, 0);
3447c478bd9Sstevel@tonic-gate 		if (copyin(ucp, &uc, sizeof (uc) -
3457c478bd9Sstevel@tonic-gate 		    sizeof (uc.uc_filler) -
3467c478bd9Sstevel@tonic-gate 		    sizeof (uc.uc_mcontext.fpregs))) {
3477c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
3487c478bd9Sstevel@tonic-gate 		}
349*8f798d3aSRoger A. Faulkner 		if (uc.uc_flags & UC_SIGMASK)
350*8f798d3aSRoger A. Faulkner 			SIGSET_BRAND_TO_NATIVE(&uc.uc_sigmask);
3517c478bd9Sstevel@tonic-gate 		if ((uc.uc_flags & UC_FPU) &&
3527c478bd9Sstevel@tonic-gate 		    copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs,
3537c478bd9Sstevel@tonic-gate 		    sizeof (uc.uc_mcontext.fpregs))) {
3547c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
3557c478bd9Sstevel@tonic-gate 		}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 		ucontext_32ton(&uc, &ucnat);
3587c478bd9Sstevel@tonic-gate 		restorecontext(&ucnat);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 		if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0))
3617c478bd9Sstevel@tonic-gate 			(void) copyout(&uc.uc_stack,
3627c478bd9Sstevel@tonic-gate 			    (stack32_t *)lwp->lwp_ustack, sizeof (uc.uc_stack));
3637c478bd9Sstevel@tonic-gate 		return (0);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	case GETUSTACK:
3667c478bd9Sstevel@tonic-gate 		ustack32 = (caddr32_t)lwp->lwp_ustack;
3677c478bd9Sstevel@tonic-gate 		if (copyout(&ustack32, arg, sizeof (ustack32)))
3687c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
3697c478bd9Sstevel@tonic-gate 		return (0);
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	case SETUSTACK:
3727c478bd9Sstevel@tonic-gate 		if (copyin(arg, &dummy_stk32, sizeof (dummy_stk32)))
3737c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
3747c478bd9Sstevel@tonic-gate 		lwp->lwp_ustack = (uintptr_t)arg;
3757c478bd9Sstevel@tonic-gate 		return (0);
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
380