xref: /illumos-gate/usr/src/uts/intel/syscall/getcontext.c (revision ed093b41a93e8563e6e1e5dae0768dda2a7bcc27)
1f0089e39SRichard Lowe /*
2f0089e39SRichard Lowe  * CDDL HEADER START
3f0089e39SRichard Lowe  *
4f0089e39SRichard Lowe  * The contents of this file are subject to the terms of the
5f0089e39SRichard Lowe  * Common Development and Distribution License (the "License").
6f0089e39SRichard Lowe  * You may not use this file except in compliance with the License.
7f0089e39SRichard Lowe  *
8f0089e39SRichard Lowe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f0089e39SRichard Lowe  * or http://www.opensolaris.org/os/licensing.
10f0089e39SRichard Lowe  * See the License for the specific language governing permissions
11f0089e39SRichard Lowe  * and limitations under the License.
12f0089e39SRichard Lowe  *
13f0089e39SRichard Lowe  * When distributing Covered Code, include this CDDL HEADER in each
14f0089e39SRichard Lowe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f0089e39SRichard Lowe  * If applicable, add the following below this CDDL HEADER, with the
16f0089e39SRichard Lowe  * fields enclosed by brackets "[]" replaced with your own identifying
17f0089e39SRichard Lowe  * information: Portions Copyright [yyyy] [name of copyright owner]
18f0089e39SRichard Lowe  *
19f0089e39SRichard Lowe  * CDDL HEADER END
20f0089e39SRichard Lowe  */
21f0089e39SRichard Lowe 
22f0089e39SRichard Lowe /*
23f0089e39SRichard Lowe  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24f0089e39SRichard Lowe  * Use is subject to license terms.
25f0089e39SRichard Lowe  */
26f0089e39SRichard Lowe 
27f0089e39SRichard Lowe /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28f0089e39SRichard Lowe /*	  All Rights Reserved	*/
29f0089e39SRichard Lowe 
30*ed093b41SRobert Mustacchi /*
31*ed093b41SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
32*ed093b41SRobert Mustacchi  */
33*ed093b41SRobert Mustacchi 
34f0089e39SRichard Lowe #include <sys/param.h>
35f0089e39SRichard Lowe #include <sys/types.h>
36f0089e39SRichard Lowe #include <sys/vmparam.h>
37f0089e39SRichard Lowe #include <sys/systm.h>
38f0089e39SRichard Lowe #include <sys/signal.h>
39f0089e39SRichard Lowe #include <sys/stack.h>
40f0089e39SRichard Lowe #include <sys/regset.h>
41f0089e39SRichard Lowe #include <sys/privregs.h>
42f0089e39SRichard Lowe #include <sys/frame.h>
43f0089e39SRichard Lowe #include <sys/proc.h>
44f0089e39SRichard Lowe #include <sys/brand.h>
45f0089e39SRichard Lowe #include <sys/psw.h>
46f0089e39SRichard Lowe #include <sys/ucontext.h>
47f0089e39SRichard Lowe #include <sys/asm_linkage.h>
48f0089e39SRichard Lowe #include <sys/errno.h>
49f0089e39SRichard Lowe #include <sys/archsystm.h>
50f0089e39SRichard Lowe #include <sys/schedctl.h>
51f0089e39SRichard Lowe #include <sys/debug.h>
52f0089e39SRichard Lowe #include <sys/sysmacros.h>
53f0089e39SRichard Lowe 
54f0089e39SRichard Lowe /*
55*ed093b41SRobert Mustacchi  * This is a wrapper around copyout_noerr that returns a guaranteed error code.
56*ed093b41SRobert Mustacchi  * Because we're using copyout_noerr(), we need to bound the time we're under an
57*ed093b41SRobert Mustacchi  * on_fault/no_fault and attempt to do so only while we're actually copying data
58*ed093b41SRobert Mustacchi  * out. The main reason for this is because we're being called back from the
59*ed093b41SRobert Mustacchi  * FPU, which is being held with a kpreempt_disable() and related, we can't use
60*ed093b41SRobert Mustacchi  * a larger on_fault()/no_fault() as that would both hide legitimate errors we
61*ed093b41SRobert Mustacchi  * make, masquerading as user issues, and it gets trickier to reason about the
62*ed093b41SRobert Mustacchi  * correct restoration of our state.
63f0089e39SRichard Lowe  */
64*ed093b41SRobert Mustacchi static int
savecontext_copyout(const void * kaddr,void * uaddr,size_t size)65*ed093b41SRobert Mustacchi savecontext_copyout(const void *kaddr, void *uaddr, size_t size)
66*ed093b41SRobert Mustacchi {
67*ed093b41SRobert Mustacchi 	label_t ljb;
68*ed093b41SRobert Mustacchi 	if (!on_fault(&ljb)) {
69*ed093b41SRobert Mustacchi 		copyout_noerr(kaddr, uaddr, size);
70*ed093b41SRobert Mustacchi 		no_fault();
71*ed093b41SRobert Mustacchi 		return (0);
72*ed093b41SRobert Mustacchi 	} else {
73*ed093b41SRobert Mustacchi 		no_fault();
74*ed093b41SRobert Mustacchi 		return (EFAULT);
75*ed093b41SRobert Mustacchi 	}
76*ed093b41SRobert Mustacchi }
77*ed093b41SRobert Mustacchi 
78*ed093b41SRobert Mustacchi /*
79*ed093b41SRobert Mustacchi  * Save user context.
80*ed093b41SRobert Mustacchi  *
81*ed093b41SRobert Mustacchi  * ucp is itself always a pointer to the kernel's copy of a ucontext_t. In the
82*ed093b41SRobert Mustacchi  * traditional version of this (when flags is 0), then we just write and fill
83*ed093b41SRobert Mustacchi  * out all of the ucontext_t without any care for what was there ahead of this.
84*ed093b41SRobert Mustacchi  * Our callers are responsible for coyping out that state if required. When
85*ed093b41SRobert Mustacchi  * there is extended state to deal with (flags include SAVECTXT_F_EXTD), our
86*ed093b41SRobert Mustacchi  * callers will have already copied in and pre-populated the structure with
87*ed093b41SRobert Mustacchi  * values from userland. When those pointers are non-zero then we will copy out
88*ed093b41SRobert Mustacchi  * that extended state directly to the user pointer. Currently this is only done
89*ed093b41SRobert Mustacchi  * for uc_xsave. Even when we perform this, the rest of the structure stays as
90*ed093b41SRobert Mustacchi  * is.
91*ed093b41SRobert Mustacchi  *
92*ed093b41SRobert Mustacchi  * We allow the copying to happen in two different ways mostly because this is
93*ed093b41SRobert Mustacchi  * also used in the signal handling context where we must be much more careful
94*ed093b41SRobert Mustacchi  * about how to copy out data.
95*ed093b41SRobert Mustacchi  */
96*ed093b41SRobert Mustacchi int
savecontext(ucontext_t * ucp,const k_sigset_t * mask,savecontext_flags_t flags)97*ed093b41SRobert Mustacchi savecontext(ucontext_t *ucp, const k_sigset_t *mask, savecontext_flags_t flags)
98f0089e39SRichard Lowe {
99f0089e39SRichard Lowe 	proc_t *p = ttoproc(curthread);
100f0089e39SRichard Lowe 	klwp_t *lwp = ttolwp(curthread);
101f0089e39SRichard Lowe 	struct regs *rp = lwptoregs(lwp);
102*ed093b41SRobert Mustacchi 	boolean_t need_xsave = B_FALSE;
103*ed093b41SRobert Mustacchi 	boolean_t fpu_en;
104*ed093b41SRobert Mustacchi 	long user_xsave = 0;
105*ed093b41SRobert Mustacchi 	int ret;
106*ed093b41SRobert Mustacchi 
107*ed093b41SRobert Mustacchi 	VERIFY0(flags & ~(SAVECTXT_F_EXTD | SAVECTXT_F_ONFAULT));
108f0089e39SRichard Lowe 
109f0089e39SRichard Lowe 	/*
110f0089e39SRichard Lowe 	 * We unconditionally assign to every field through the end
111f0089e39SRichard Lowe 	 * of the gregs, but we need to bzero() everything -after- that
112f0089e39SRichard Lowe 	 * to avoid having any kernel stack garbage escape to userland.
113*ed093b41SRobert Mustacchi 	 *
114*ed093b41SRobert Mustacchi 	 * If we have been asked to save extended state, then we must make sure
115*ed093b41SRobert Mustacchi 	 * that we don't clobber that value. We must also determine if the
116*ed093b41SRobert Mustacchi 	 * processor has xsave state. If it does not, then we just simply honor
117*ed093b41SRobert Mustacchi 	 * the pointer, but do not write anything out and do not set the flag.
118f0089e39SRichard Lowe 	 */
119*ed093b41SRobert Mustacchi 	if ((flags & SAVECTXT_F_EXTD) != 0) {
120*ed093b41SRobert Mustacchi 		user_xsave = ucp->uc_xsave;
121*ed093b41SRobert Mustacchi 		if (fpu_xsave_enabled() && user_xsave != 0) {
122*ed093b41SRobert Mustacchi 			need_xsave = B_TRUE;
123*ed093b41SRobert Mustacchi 		}
124*ed093b41SRobert Mustacchi 	} else {
125*ed093b41SRobert Mustacchi 		/*
126*ed093b41SRobert Mustacchi 		 * The only other flag that we have right now is about modifying
127*ed093b41SRobert Mustacchi 		 * the copyout behavior when we're copying out extended
128*ed093b41SRobert Mustacchi 		 * information. If it's not here, we should not do anything.
129*ed093b41SRobert Mustacchi 		 */
130*ed093b41SRobert Mustacchi 		VERIFY0(flags);
131*ed093b41SRobert Mustacchi 	}
132f0089e39SRichard Lowe 	bzero(&ucp->uc_mcontext.fpregs, sizeof (ucontext_t) -
133f0089e39SRichard Lowe 	    offsetof(ucontext_t, uc_mcontext.fpregs));
134*ed093b41SRobert Mustacchi 	ucp->uc_xsave = user_xsave;
135f0089e39SRichard Lowe 
136f0089e39SRichard Lowe 	ucp->uc_flags = UC_ALL;
137f0089e39SRichard Lowe 	ucp->uc_link = (struct ucontext *)lwp->lwp_oldcontext;
138f0089e39SRichard Lowe 
139f0089e39SRichard Lowe 	/*
140f0089e39SRichard Lowe 	 * Try to copyin() the ustack if one is registered. If the stack
141f0089e39SRichard Lowe 	 * has zero size, this indicates that stack bounds checking has
142f0089e39SRichard Lowe 	 * been disabled for this LWP. If stack bounds checking is disabled
143f0089e39SRichard Lowe 	 * or the copyin() fails, we fall back to the legacy behavior.
144f0089e39SRichard Lowe 	 */
145f0089e39SRichard Lowe 	if (lwp->lwp_ustack == (uintptr_t)NULL ||
146f0089e39SRichard Lowe 	    copyin((void *)lwp->lwp_ustack, &ucp->uc_stack,
147f0089e39SRichard Lowe 	    sizeof (ucp->uc_stack)) != 0 ||
148f0089e39SRichard Lowe 	    ucp->uc_stack.ss_size == 0) {
149f0089e39SRichard Lowe 
150f0089e39SRichard Lowe 		if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) {
151f0089e39SRichard Lowe 			ucp->uc_stack = lwp->lwp_sigaltstack;
152f0089e39SRichard Lowe 		} else {
153f0089e39SRichard Lowe 			ucp->uc_stack.ss_sp = p->p_usrstack - p->p_stksize;
154f0089e39SRichard Lowe 			ucp->uc_stack.ss_size = p->p_stksize;
155f0089e39SRichard Lowe 			ucp->uc_stack.ss_flags = 0;
156f0089e39SRichard Lowe 		}
157f0089e39SRichard Lowe 	}
158f0089e39SRichard Lowe 
159f0089e39SRichard Lowe 	/*
160f0089e39SRichard Lowe 	 * If either the trace flag or REQUEST_STEP is set,
161f0089e39SRichard Lowe 	 * arrange for single-stepping and turn off the trace flag.
162f0089e39SRichard Lowe 	 */
163f0089e39SRichard Lowe 	if ((rp->r_ps & PS_T) || (lwp->lwp_pcb.pcb_flags & REQUEST_STEP)) {
164f0089e39SRichard Lowe 		/*
165f0089e39SRichard Lowe 		 * Clear PS_T so that saved user context won't have trace
166f0089e39SRichard Lowe 		 * flag set.
167f0089e39SRichard Lowe 		 */
168f0089e39SRichard Lowe 		rp->r_ps &= ~PS_T;
169f0089e39SRichard Lowe 
170f0089e39SRichard Lowe 		if (!(lwp->lwp_pcb.pcb_flags & REQUEST_NOSTEP)) {
171f0089e39SRichard Lowe 			lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
172f0089e39SRichard Lowe 			/*
173f0089e39SRichard Lowe 			 * trap() always checks DEBUG_PENDING before
174f0089e39SRichard Lowe 			 * checking for any pending signal. This at times
175f0089e39SRichard Lowe 			 * can potentially lead to DEBUG_PENDING not being
176f0089e39SRichard Lowe 			 * honoured. (for eg: the lwp is stopped by
177f0089e39SRichard Lowe 			 * stop_on_fault() called from trap(), after being
178f0089e39SRichard Lowe 			 * awakened it might see a pending signal and call
179f0089e39SRichard Lowe 			 * savecontext(), however on the way back to userland
180f0089e39SRichard Lowe 			 * there is no place it can be detected). Hence in
181*ed093b41SRobert Mustacchi 			 * anticipation of such occasions, set AST flag for
182f0089e39SRichard Lowe 			 * the thread which will make the thread take an
183f0089e39SRichard Lowe 			 * excursion through trap() where it will be handled
184f0089e39SRichard Lowe 			 * appropriately.
185f0089e39SRichard Lowe 			 */
186f0089e39SRichard Lowe 			aston(curthread);
187f0089e39SRichard Lowe 		}
188f0089e39SRichard Lowe 	}
189f0089e39SRichard Lowe 
190f0089e39SRichard Lowe 	getgregs(lwp, ucp->uc_mcontext.gregs);
191*ed093b41SRobert Mustacchi 	fpu_en = (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN) != 0;
192*ed093b41SRobert Mustacchi 	if (fpu_en)
193f0089e39SRichard Lowe 		getfpregs(lwp, &ucp->uc_mcontext.fpregs);
194f0089e39SRichard Lowe 	else
195f0089e39SRichard Lowe 		ucp->uc_flags &= ~UC_FPU;
196f0089e39SRichard Lowe 
197f0089e39SRichard Lowe 	sigktou(mask, &ucp->uc_sigmask);
198*ed093b41SRobert Mustacchi 
199*ed093b41SRobert Mustacchi 	/*
200*ed093b41SRobert Mustacchi 	 * Determine if we need to get the rest of the xsave context out here.
201*ed093b41SRobert Mustacchi 	 * If the thread doesn't actually have the FPU enabled, then we don't
202*ed093b41SRobert Mustacchi 	 * actually need to do this. We also don't have to if it wasn't
203*ed093b41SRobert Mustacchi 	 * requested.
204*ed093b41SRobert Mustacchi 	 */
205*ed093b41SRobert Mustacchi 	if (!need_xsave || !fpu_en) {
206*ed093b41SRobert Mustacchi 		return (0);
207*ed093b41SRobert Mustacchi 	}
208*ed093b41SRobert Mustacchi 
209*ed093b41SRobert Mustacchi 	ucp->uc_flags |= UC_XSAVE;
210*ed093b41SRobert Mustacchi 
211*ed093b41SRobert Mustacchi 	/*
212*ed093b41SRobert Mustacchi 	 * While you might be asking why and contemplating despair, just know
213*ed093b41SRobert Mustacchi 	 * that some things need to just be done in the face of signal (half the
214*ed093b41SRobert Mustacchi 	 * reason this function exists). Basically when in signal context we
215*ed093b41SRobert Mustacchi 	 * can't trigger watch points. This means we need to tell the FPU copy
216*ed093b41SRobert Mustacchi 	 * logic to actually use the on_fault/no_fault and the non-error form of
217*ed093b41SRobert Mustacchi 	 * copyout (which still checks if it's a user address at least).
218*ed093b41SRobert Mustacchi 	 */
219*ed093b41SRobert Mustacchi 	if ((flags & SAVECTXT_F_ONFAULT) != 0) {
220*ed093b41SRobert Mustacchi 		ret = fpu_signal_copyout(lwp, ucp->uc_xsave,
221*ed093b41SRobert Mustacchi 		    savecontext_copyout);
222*ed093b41SRobert Mustacchi 	} else {
223*ed093b41SRobert Mustacchi 		ret = fpu_signal_copyout(lwp, ucp->uc_xsave, copyout);
224*ed093b41SRobert Mustacchi 	}
225*ed093b41SRobert Mustacchi 
226*ed093b41SRobert Mustacchi 	return (ret);
227f0089e39SRichard Lowe }
228f0089e39SRichard Lowe 
229f0089e39SRichard Lowe /*
230f0089e39SRichard Lowe  * Restore user context.
231f0089e39SRichard Lowe  */
232f0089e39SRichard Lowe void
restorecontext(ucontext_t * ucp)233f0089e39SRichard Lowe restorecontext(ucontext_t *ucp)
234f0089e39SRichard Lowe {
235f0089e39SRichard Lowe 	kthread_t *t = curthread;
236f0089e39SRichard Lowe 	klwp_t *lwp = ttolwp(t);
237f0089e39SRichard Lowe 
238f0089e39SRichard Lowe 	lwp->lwp_oldcontext = (uintptr_t)ucp->uc_link;
239f0089e39SRichard Lowe 
240f0089e39SRichard Lowe 	if (ucp->uc_flags & UC_STACK) {
241f0089e39SRichard Lowe 		if (ucp->uc_stack.ss_flags == SS_ONSTACK)
242f0089e39SRichard Lowe 			lwp->lwp_sigaltstack = ucp->uc_stack;
243f0089e39SRichard Lowe 		else
244f0089e39SRichard Lowe 			lwp->lwp_sigaltstack.ss_flags &= ~SS_ONSTACK;
245f0089e39SRichard Lowe 	}
246f0089e39SRichard Lowe 
247f0089e39SRichard Lowe 	if (ucp->uc_flags & UC_CPU) {
248f0089e39SRichard Lowe 		/*
249f0089e39SRichard Lowe 		 * If the trace flag is set, mark the lwp to take a
250f0089e39SRichard Lowe 		 * single-step trap on return to user level (below).
251f0089e39SRichard Lowe 		 * The x86 lcall interface and sysenter has already done this,
252f0089e39SRichard Lowe 		 * and turned off the flag, but amd64 syscall interface has not.
253f0089e39SRichard Lowe 		 */
254f0089e39SRichard Lowe 		if (lwptoregs(lwp)->r_ps & PS_T)
255f0089e39SRichard Lowe 			lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
256f0089e39SRichard Lowe 		setgregs(lwp, ucp->uc_mcontext.gregs);
257f0089e39SRichard Lowe 		lwp->lwp_eosys = JUSTRETURN;
258f0089e39SRichard Lowe 		t->t_post_sys = 1;
259f0089e39SRichard Lowe 		aston(curthread);
260f0089e39SRichard Lowe 	}
261f0089e39SRichard Lowe 
262*ed093b41SRobert Mustacchi 	/*
263*ed093b41SRobert Mustacchi 	 * The logic to copy in the ucontex_t takes care of combining the UC_FPU
264*ed093b41SRobert Mustacchi 	 * and UC_XSAVE, so at this point only one of them should be set, if
265*ed093b41SRobert Mustacchi 	 * any.
266*ed093b41SRobert Mustacchi 	 */
267*ed093b41SRobert Mustacchi 	if (ucp->uc_flags & UC_XSAVE) {
268*ed093b41SRobert Mustacchi 		ASSERT0(ucp->uc_flags & UC_FPU);
269*ed093b41SRobert Mustacchi 		ASSERT3U((uintptr_t)ucp->uc_xsave, >=, _kernelbase);
270*ed093b41SRobert Mustacchi 		fpu_set_xsave(lwp, (const void *)ucp->uc_xsave);
271*ed093b41SRobert Mustacchi 	} else if (ucp->uc_flags & UC_FPU) {
272f0089e39SRichard Lowe 		setfpregs(lwp, &ucp->uc_mcontext.fpregs);
273*ed093b41SRobert Mustacchi 	}
274f0089e39SRichard Lowe 
275f0089e39SRichard Lowe 	if (ucp->uc_flags & UC_SIGMASK) {
276f0089e39SRichard Lowe 		/*
277f0089e39SRichard Lowe 		 * We don't need to acquire p->p_lock here;
278f0089e39SRichard Lowe 		 * we are manipulating thread-private data.
279f0089e39SRichard Lowe 		 */
280f0089e39SRichard Lowe 		schedctl_finish_sigblock(t);
281f0089e39SRichard Lowe 		sigutok(&ucp->uc_sigmask, &t->t_hold);
282f0089e39SRichard Lowe 		if (sigcheck(ttoproc(t), t))
283f0089e39SRichard Lowe 			t->t_sig_check = 1;
284f0089e39SRichard Lowe 	}
285f0089e39SRichard Lowe }
286f0089e39SRichard Lowe 
287f0089e39SRichard Lowe 
288f0089e39SRichard Lowe int
getsetcontext(int flag,void * arg)289f0089e39SRichard Lowe getsetcontext(int flag, void *arg)
290f0089e39SRichard Lowe {
291f0089e39SRichard Lowe 	ucontext_t uc;
292f0089e39SRichard Lowe 	ucontext_t *ucp;
293f0089e39SRichard Lowe 	klwp_t *lwp = ttolwp(curthread);
294*ed093b41SRobert Mustacchi 	void *fpu = NULL;
295f0089e39SRichard Lowe 	stack_t dummy_stk;
296*ed093b41SRobert Mustacchi 	int ret;
297f0089e39SRichard Lowe 
298f0089e39SRichard Lowe 	/*
299f0089e39SRichard Lowe 	 * In future releases, when the ucontext structure grows,
300f0089e39SRichard Lowe 	 * getcontext should be modified to only return the fields
301f0089e39SRichard Lowe 	 * specified in the uc_flags.  That way, the structure can grow
302f0089e39SRichard Lowe 	 * and still be binary compatible will all .o's which will only
303f0089e39SRichard Lowe 	 * have old fields defined in uc_flags
304f0089e39SRichard Lowe 	 */
305f0089e39SRichard Lowe 
306f0089e39SRichard Lowe 	switch (flag) {
307f0089e39SRichard Lowe 	default:
308f0089e39SRichard Lowe 		return (set_errno(EINVAL));
309f0089e39SRichard Lowe 
310f0089e39SRichard Lowe 	case GETCONTEXT:
311f0089e39SRichard Lowe 		schedctl_finish_sigblock(curthread);
312*ed093b41SRobert Mustacchi 		ret = savecontext(&uc, &curthread->t_hold, SAVECTXT_F_NONE);
313*ed093b41SRobert Mustacchi 		if (ret != 0)
314*ed093b41SRobert Mustacchi 			return (set_errno(ret));
315f0089e39SRichard Lowe 		if (uc.uc_flags & UC_SIGMASK)
316f0089e39SRichard Lowe 			SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
317f0089e39SRichard Lowe 		if (copyout(&uc, arg, sizeof (uc)))
318f0089e39SRichard Lowe 			return (set_errno(EFAULT));
319f0089e39SRichard Lowe 		return (0);
320f0089e39SRichard Lowe 
321*ed093b41SRobert Mustacchi 	/*
322*ed093b41SRobert Mustacchi 	 * In the case of GETCONTEXT_EXTD, we've theoretically been given all
323*ed093b41SRobert Mustacchi 	 * the required pointers of the appropriate length by libc in the
324*ed093b41SRobert Mustacchi 	 * ucontext_t. We must first copyin the offsets that we care about to
325*ed093b41SRobert Mustacchi 	 * seed the known extensions. Right now that is just the uc_xsave
326*ed093b41SRobert Mustacchi 	 * member. As we are setting uc_flags, we only look at the members we
327*ed093b41SRobert Mustacchi 	 * need to care about.
328*ed093b41SRobert Mustacchi 	 *
329*ed093b41SRobert Mustacchi 	 * The main reason that we have a different entry point is that we don't
330*ed093b41SRobert Mustacchi 	 * want to assume that callers have always properly zeroed their
331*ed093b41SRobert Mustacchi 	 * ucontext_t ahead of calling into libc. In fact, it often is just
332*ed093b41SRobert Mustacchi 	 * declared on the stack so we can't assume that at all. Instead,
333*ed093b41SRobert Mustacchi 	 * getcontext_extd does require that.
334*ed093b41SRobert Mustacchi 	 */
335*ed093b41SRobert Mustacchi 	case GETCONTEXT_EXTD:
336*ed093b41SRobert Mustacchi 		schedctl_finish_sigblock(curthread);
337*ed093b41SRobert Mustacchi 		ucp = arg;
338*ed093b41SRobert Mustacchi 		if (copyin(&ucp->uc_xsave, &uc.uc_xsave,
339*ed093b41SRobert Mustacchi 		    sizeof (uc.uc_xsave)) != 0) {
340*ed093b41SRobert Mustacchi 			return (set_errno(EFAULT));
341*ed093b41SRobert Mustacchi 		}
342*ed093b41SRobert Mustacchi 		ret = savecontext(&uc, &curthread->t_hold, SAVECTXT_F_EXTD);
343*ed093b41SRobert Mustacchi 		if (ret != 0)
344*ed093b41SRobert Mustacchi 			return (set_errno(ret));
345*ed093b41SRobert Mustacchi 		if (uc.uc_flags & UC_SIGMASK)
346*ed093b41SRobert Mustacchi 			SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
347*ed093b41SRobert Mustacchi 		if (copyout(&uc, arg, sizeof (uc)))
348*ed093b41SRobert Mustacchi 			return (set_errno(EFAULT));
349*ed093b41SRobert Mustacchi 		return (0);
350*ed093b41SRobert Mustacchi 
351*ed093b41SRobert Mustacchi 
352f0089e39SRichard Lowe 	case SETCONTEXT:
353f0089e39SRichard Lowe 		ucp = arg;
354f0089e39SRichard Lowe 		if (ucp == NULL)
355f0089e39SRichard Lowe 			exit(CLD_EXITED, 0);
356f0089e39SRichard Lowe 		/*
357f0089e39SRichard Lowe 		 * Don't copyin filler or floating state unless we need it.
358f0089e39SRichard Lowe 		 * The ucontext_t struct and fields are specified in the ABI.
359f0089e39SRichard Lowe 		 */
360*ed093b41SRobert Mustacchi 		if (copyin(ucp, &uc, offsetof(ucontext_t, uc_filler) -
361f0089e39SRichard Lowe 		    sizeof (uc.uc_mcontext.fpregs))) {
362f0089e39SRichard Lowe 			return (set_errno(EFAULT));
363f0089e39SRichard Lowe 		}
364f0089e39SRichard Lowe 		if (uc.uc_flags & UC_SIGMASK)
365f0089e39SRichard Lowe 			SIGSET_BRAND_TO_NATIVE(&uc.uc_sigmask);
366f0089e39SRichard Lowe 
367f0089e39SRichard Lowe 		if ((uc.uc_flags & UC_FPU) &&
368f0089e39SRichard Lowe 		    copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs,
369f0089e39SRichard Lowe 		    sizeof (uc.uc_mcontext.fpregs))) {
370f0089e39SRichard Lowe 			return (set_errno(EFAULT));
371f0089e39SRichard Lowe 		}
372f0089e39SRichard Lowe 
373*ed093b41SRobert Mustacchi 		uc.uc_xsave = 0;
374*ed093b41SRobert Mustacchi 		if ((uc.uc_flags & UC_XSAVE) != 0) {
375*ed093b41SRobert Mustacchi 			int ret;
376*ed093b41SRobert Mustacchi 
377*ed093b41SRobert Mustacchi 			if (copyin(&ucp->uc_xsave, &uc.uc_xsave,
378*ed093b41SRobert Mustacchi 			    sizeof (uc.uc_xsave)) != 0) {
379*ed093b41SRobert Mustacchi 				return (set_errno(EFAULT));
380*ed093b41SRobert Mustacchi 			}
381*ed093b41SRobert Mustacchi 
382*ed093b41SRobert Mustacchi 			ret = fpu_signal_copyin(lwp, &uc);
383*ed093b41SRobert Mustacchi 			if (ret != 0) {
384*ed093b41SRobert Mustacchi 				return (set_errno(ret));
385*ed093b41SRobert Mustacchi 			}
386*ed093b41SRobert Mustacchi 		}
387*ed093b41SRobert Mustacchi 
388f0089e39SRichard Lowe 		restorecontext(&uc);
389f0089e39SRichard Lowe 
390f0089e39SRichard Lowe 		if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0))
391f0089e39SRichard Lowe 			(void) copyout(&uc.uc_stack, (stack_t *)lwp->lwp_ustack,
392f0089e39SRichard Lowe 			    sizeof (uc.uc_stack));
393f0089e39SRichard Lowe 		return (0);
394f0089e39SRichard Lowe 
395f0089e39SRichard Lowe 	case GETUSTACK:
396f0089e39SRichard Lowe 		if (copyout(&lwp->lwp_ustack, arg, sizeof (caddr_t)))
397f0089e39SRichard Lowe 			return (set_errno(EFAULT));
398f0089e39SRichard Lowe 		return (0);
399f0089e39SRichard Lowe 
400f0089e39SRichard Lowe 	case SETUSTACK:
401f0089e39SRichard Lowe 		if (copyin(arg, &dummy_stk, sizeof (dummy_stk)))
402f0089e39SRichard Lowe 			return (set_errno(EFAULT));
403f0089e39SRichard Lowe 		lwp->lwp_ustack = (uintptr_t)arg;
404f0089e39SRichard Lowe 		return (0);
405f0089e39SRichard Lowe 	}
406f0089e39SRichard Lowe }
407f0089e39SRichard Lowe 
408f0089e39SRichard Lowe #ifdef _SYSCALL32_IMPL
409f0089e39SRichard Lowe 
410f0089e39SRichard Lowe /*
411f0089e39SRichard Lowe  * Save user context for 32-bit processes.
412f0089e39SRichard Lowe  */
413*ed093b41SRobert Mustacchi int
savecontext32(ucontext32_t * ucp,const k_sigset_t * mask,savecontext_flags_t flags)414*ed093b41SRobert Mustacchi savecontext32(ucontext32_t *ucp, const k_sigset_t *mask,
415*ed093b41SRobert Mustacchi     savecontext_flags_t flags)
416f0089e39SRichard Lowe {
417f0089e39SRichard Lowe 	proc_t *p = ttoproc(curthread);
418f0089e39SRichard Lowe 	klwp_t *lwp = ttolwp(curthread);
419f0089e39SRichard Lowe 	struct regs *rp = lwptoregs(lwp);
420*ed093b41SRobert Mustacchi 	boolean_t need_xsave = B_FALSE;
421*ed093b41SRobert Mustacchi 	boolean_t fpu_en;
422*ed093b41SRobert Mustacchi 	int32_t user_xsave = 0;
423*ed093b41SRobert Mustacchi 	uintptr_t uaddr;
424*ed093b41SRobert Mustacchi 	int ret;
425f0089e39SRichard Lowe 
426*ed093b41SRobert Mustacchi 	/*
427*ed093b41SRobert Mustacchi 	 * See savecontext for an explanation of this.
428*ed093b41SRobert Mustacchi 	 */
429*ed093b41SRobert Mustacchi 	if ((flags & SAVECTXT_F_EXTD) != 0) {
430*ed093b41SRobert Mustacchi 		user_xsave = ucp->uc_xsave;
431*ed093b41SRobert Mustacchi 		if (fpu_xsave_enabled() && user_xsave != 0) {
432*ed093b41SRobert Mustacchi 			need_xsave = B_TRUE;
433*ed093b41SRobert Mustacchi 		}
434*ed093b41SRobert Mustacchi 	} else {
435*ed093b41SRobert Mustacchi 		VERIFY0(flags);
436*ed093b41SRobert Mustacchi 	}
437f0089e39SRichard Lowe 	bzero(&ucp->uc_mcontext.fpregs, sizeof (ucontext32_t) -
438f0089e39SRichard Lowe 	    offsetof(ucontext32_t, uc_mcontext.fpregs));
439*ed093b41SRobert Mustacchi 	ucp->uc_xsave = user_xsave;
440f0089e39SRichard Lowe 
441f0089e39SRichard Lowe 	ucp->uc_flags = UC_ALL;
442f0089e39SRichard Lowe 	ucp->uc_link = (caddr32_t)lwp->lwp_oldcontext;
443f0089e39SRichard Lowe 
444f0089e39SRichard Lowe 	if (lwp->lwp_ustack == (uintptr_t)NULL ||
445f0089e39SRichard Lowe 	    copyin((void *)lwp->lwp_ustack, &ucp->uc_stack,
446f0089e39SRichard Lowe 	    sizeof (ucp->uc_stack)) != 0 ||
447f0089e39SRichard Lowe 	    ucp->uc_stack.ss_size == 0) {
448f0089e39SRichard Lowe 
449f0089e39SRichard Lowe 		if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) {
450f0089e39SRichard Lowe 			ucp->uc_stack.ss_sp =
451f0089e39SRichard Lowe 			    (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
452f0089e39SRichard Lowe 			ucp->uc_stack.ss_size =
453f0089e39SRichard Lowe 			    (size32_t)lwp->lwp_sigaltstack.ss_size;
454f0089e39SRichard Lowe 			ucp->uc_stack.ss_flags = SS_ONSTACK;
455f0089e39SRichard Lowe 		} else {
456f0089e39SRichard Lowe 			ucp->uc_stack.ss_sp = (caddr32_t)(uintptr_t)
457f0089e39SRichard Lowe 			    (p->p_usrstack - p->p_stksize);
458f0089e39SRichard Lowe 			ucp->uc_stack.ss_size = (size32_t)p->p_stksize;
459f0089e39SRichard Lowe 			ucp->uc_stack.ss_flags = 0;
460f0089e39SRichard Lowe 		}
461f0089e39SRichard Lowe 	}
462f0089e39SRichard Lowe 
463f0089e39SRichard Lowe 	/*
464f0089e39SRichard Lowe 	 * If either the trace flag or REQUEST_STEP is set, arrange
465f0089e39SRichard Lowe 	 * for single-stepping and turn off the trace flag.
466f0089e39SRichard Lowe 	 */
467f0089e39SRichard Lowe 	if ((rp->r_ps & PS_T) || (lwp->lwp_pcb.pcb_flags & REQUEST_STEP)) {
468f0089e39SRichard Lowe 		/*
469f0089e39SRichard Lowe 		 * Clear PS_T so that saved user context won't have trace
470f0089e39SRichard Lowe 		 * flag set.
471f0089e39SRichard Lowe 		 */
472f0089e39SRichard Lowe 		rp->r_ps &= ~PS_T;
473f0089e39SRichard Lowe 
474f0089e39SRichard Lowe 		if (!(lwp->lwp_pcb.pcb_flags & REQUEST_NOSTEP)) {
475f0089e39SRichard Lowe 			lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
476f0089e39SRichard Lowe 			/*
477f0089e39SRichard Lowe 			 * See comments in savecontext().
478f0089e39SRichard Lowe 			 */
479f0089e39SRichard Lowe 			aston(curthread);
480f0089e39SRichard Lowe 		}
481f0089e39SRichard Lowe 	}
482f0089e39SRichard Lowe 
483f0089e39SRichard Lowe 	getgregs32(lwp, ucp->uc_mcontext.gregs);
484*ed093b41SRobert Mustacchi 	fpu_en = (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN) != 0;
485*ed093b41SRobert Mustacchi 	if (fpu_en)
486f0089e39SRichard Lowe 		getfpregs32(lwp, &ucp->uc_mcontext.fpregs);
487f0089e39SRichard Lowe 	else
488f0089e39SRichard Lowe 		ucp->uc_flags &= ~UC_FPU;
489f0089e39SRichard Lowe 
490f0089e39SRichard Lowe 	sigktou(mask, &ucp->uc_sigmask);
491*ed093b41SRobert Mustacchi 
492*ed093b41SRobert Mustacchi 	if (!need_xsave || !fpu_en) {
493*ed093b41SRobert Mustacchi 		return (0);
494*ed093b41SRobert Mustacchi 	}
495*ed093b41SRobert Mustacchi 
496*ed093b41SRobert Mustacchi 	ucp->uc_flags |= UC_XSAVE;
497*ed093b41SRobert Mustacchi 
498*ed093b41SRobert Mustacchi 	/*
499*ed093b41SRobert Mustacchi 	 * Due to not wanting to change or break programs, the filler in the
500*ed093b41SRobert Mustacchi 	 * ucontext_t was always declared as a long, which is signed. Because
501*ed093b41SRobert Mustacchi 	 * this is the 32-bit version, this is an int32_t. We cannot directly go
502*ed093b41SRobert Mustacchi 	 * to a uintptr_t otherwise we might get sign extension, so we first
503*ed093b41SRobert Mustacchi 	 * have to go through a uint32_t and then a uintptr_t. Otherwise, see
504*ed093b41SRobert Mustacchi 	 * savecontext().
505*ed093b41SRobert Mustacchi 	 */
506*ed093b41SRobert Mustacchi 	uaddr = (uintptr_t)(uint32_t)ucp->uc_xsave;
507*ed093b41SRobert Mustacchi 	if ((flags & SAVECTXT_F_ONFAULT) != 0) {
508*ed093b41SRobert Mustacchi 		ret = fpu_signal_copyout(lwp, uaddr, savecontext_copyout);
509*ed093b41SRobert Mustacchi 	} else {
510*ed093b41SRobert Mustacchi 		ret = fpu_signal_copyout(lwp, uaddr, copyout);
511*ed093b41SRobert Mustacchi 	}
512*ed093b41SRobert Mustacchi 
513*ed093b41SRobert Mustacchi 	return (ret);
514f0089e39SRichard Lowe }
515f0089e39SRichard Lowe 
516f0089e39SRichard Lowe int
getsetcontext32(int flag,void * arg)517f0089e39SRichard Lowe getsetcontext32(int flag, void *arg)
518f0089e39SRichard Lowe {
519f0089e39SRichard Lowe 	ucontext32_t uc;
520f0089e39SRichard Lowe 	ucontext_t ucnat;
521f0089e39SRichard Lowe 	ucontext32_t *ucp;
522f0089e39SRichard Lowe 	klwp_t *lwp = ttolwp(curthread);
523f0089e39SRichard Lowe 	caddr32_t ustack32;
524f0089e39SRichard Lowe 	stack32_t dummy_stk32;
525*ed093b41SRobert Mustacchi 	int ret;
526f0089e39SRichard Lowe 
527f0089e39SRichard Lowe 	switch (flag) {
528f0089e39SRichard Lowe 	default:
529f0089e39SRichard Lowe 		return (set_errno(EINVAL));
530f0089e39SRichard Lowe 
531f0089e39SRichard Lowe 	case GETCONTEXT:
532f0089e39SRichard Lowe 		schedctl_finish_sigblock(curthread);
533*ed093b41SRobert Mustacchi 		ret = savecontext32(&uc, &curthread->t_hold, SAVECTXT_F_NONE);
534*ed093b41SRobert Mustacchi 		if (ret != 0)
535*ed093b41SRobert Mustacchi 			return (set_errno(ret));
536*ed093b41SRobert Mustacchi 		if (uc.uc_flags & UC_SIGMASK)
537*ed093b41SRobert Mustacchi 			SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
538*ed093b41SRobert Mustacchi 		if (copyout(&uc, arg, sizeof (uc)))
539*ed093b41SRobert Mustacchi 			return (set_errno(EFAULT));
540*ed093b41SRobert Mustacchi 		return (0);
541*ed093b41SRobert Mustacchi 
542*ed093b41SRobert Mustacchi 	/*
543*ed093b41SRobert Mustacchi 	 * See getsetcontext() for an explanation of what is going on here.
544*ed093b41SRobert Mustacchi 	 */
545*ed093b41SRobert Mustacchi 	case GETCONTEXT_EXTD:
546*ed093b41SRobert Mustacchi 		schedctl_finish_sigblock(curthread);
547*ed093b41SRobert Mustacchi 		ucp = arg;
548*ed093b41SRobert Mustacchi 		if (copyin(&ucp->uc_xsave, &uc.uc_xsave,
549*ed093b41SRobert Mustacchi 		    sizeof (uc.uc_xsave)) != 0) {
550*ed093b41SRobert Mustacchi 			return (set_errno(EFAULT));
551*ed093b41SRobert Mustacchi 		}
552*ed093b41SRobert Mustacchi 		ret = savecontext32(&uc, &curthread->t_hold, SAVECTXT_F_EXTD);
553*ed093b41SRobert Mustacchi 		if (ret != 0)
554*ed093b41SRobert Mustacchi 			return (set_errno(ret));
555f0089e39SRichard Lowe 		if (uc.uc_flags & UC_SIGMASK)
556f0089e39SRichard Lowe 			SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
557f0089e39SRichard Lowe 		if (copyout(&uc, arg, sizeof (uc)))
558f0089e39SRichard Lowe 			return (set_errno(EFAULT));
559f0089e39SRichard Lowe 		return (0);
560f0089e39SRichard Lowe 
561f0089e39SRichard Lowe 	case SETCONTEXT:
562f0089e39SRichard Lowe 		ucp = arg;
563f0089e39SRichard Lowe 		if (ucp == NULL)
564f0089e39SRichard Lowe 			exit(CLD_EXITED, 0);
565*ed093b41SRobert Mustacchi 		if (copyin(ucp, &uc, offsetof(ucontext32_t, uc_filler) -
566f0089e39SRichard Lowe 		    sizeof (uc.uc_mcontext.fpregs))) {
567f0089e39SRichard Lowe 			return (set_errno(EFAULT));
568f0089e39SRichard Lowe 		}
569f0089e39SRichard Lowe 		if (uc.uc_flags & UC_SIGMASK)
570f0089e39SRichard Lowe 			SIGSET_BRAND_TO_NATIVE(&uc.uc_sigmask);
571f0089e39SRichard Lowe 		if ((uc.uc_flags & UC_FPU) &&
572f0089e39SRichard Lowe 		    copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs,
573f0089e39SRichard Lowe 		    sizeof (uc.uc_mcontext.fpregs))) {
574f0089e39SRichard Lowe 			return (set_errno(EFAULT));
575f0089e39SRichard Lowe 		}
576f0089e39SRichard Lowe 
577*ed093b41SRobert Mustacchi 		uc.uc_xsave = 0;
578*ed093b41SRobert Mustacchi 		if ((uc.uc_flags & UC_XSAVE) != 0 &&
579*ed093b41SRobert Mustacchi 		    copyin(&ucp->uc_xsave, &uc.uc_xsave,
580*ed093b41SRobert Mustacchi 		    sizeof (uc.uc_xsave)) != 0) {
581*ed093b41SRobert Mustacchi 			return (set_errno(EFAULT));
582*ed093b41SRobert Mustacchi 		}
583*ed093b41SRobert Mustacchi 
584f0089e39SRichard Lowe 		ucontext_32ton(&uc, &ucnat);
585*ed093b41SRobert Mustacchi 
586*ed093b41SRobert Mustacchi 		if ((ucnat.uc_flags & UC_XSAVE) != 0) {
587*ed093b41SRobert Mustacchi 			int ret = fpu_signal_copyin(lwp, &ucnat);
588*ed093b41SRobert Mustacchi 			if (ret != 0) {
589*ed093b41SRobert Mustacchi 				return (set_errno(ret));
590*ed093b41SRobert Mustacchi 			}
591*ed093b41SRobert Mustacchi 		}
592*ed093b41SRobert Mustacchi 
593f0089e39SRichard Lowe 		restorecontext(&ucnat);
594f0089e39SRichard Lowe 
595f0089e39SRichard Lowe 		if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0))
596f0089e39SRichard Lowe 			(void) copyout(&uc.uc_stack,
597f0089e39SRichard Lowe 			    (stack32_t *)lwp->lwp_ustack, sizeof (uc.uc_stack));
598f0089e39SRichard Lowe 		return (0);
599f0089e39SRichard Lowe 
600f0089e39SRichard Lowe 	case GETUSTACK:
601f0089e39SRichard Lowe 		ustack32 = (caddr32_t)lwp->lwp_ustack;
602f0089e39SRichard Lowe 		if (copyout(&ustack32, arg, sizeof (ustack32)))
603f0089e39SRichard Lowe 			return (set_errno(EFAULT));
604f0089e39SRichard Lowe 		return (0);
605f0089e39SRichard Lowe 
606f0089e39SRichard Lowe 	case SETUSTACK:
607f0089e39SRichard Lowe 		if (copyin(arg, &dummy_stk32, sizeof (dummy_stk32)))
608f0089e39SRichard Lowe 			return (set_errno(EFAULT));
609f0089e39SRichard Lowe 		lwp->lwp_ustack = (uintptr_t)arg;
610f0089e39SRichard Lowe 		return (0);
611f0089e39SRichard Lowe 	}
612f0089e39SRichard Lowe }
613f0089e39SRichard Lowe 
614f0089e39SRichard Lowe #endif	/* _SYSCALL32_IMPL */
615