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