getcontext.c revision 11913:283e725df792
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28/*	  All Rights Reserved  	*/
29
30#include <sys/param.h>
31#include <sys/types.h>
32#include <sys/vmparam.h>
33#include <sys/systm.h>
34#include <sys/signal.h>
35#include <sys/stack.h>
36#include <sys/frame.h>
37#include <sys/proc.h>
38#include <sys/ucontext.h>
39#include <sys/asm_linkage.h>
40#include <sys/kmem.h>
41#include <sys/errno.h>
42#include <sys/archsystm.h>
43#include <sys/fpu/fpusystm.h>
44#include <sys/debug.h>
45#include <sys/model.h>
46#include <sys/cmn_err.h>
47#include <sys/sysmacros.h>
48#include <sys/privregs.h>
49#include <sys/schedctl.h>
50
51
52/*
53 * Save user context.
54 */
55void
56savecontext(ucontext_t *ucp, const k_sigset_t *mask)
57{
58	proc_t *p = ttoproc(curthread);
59	klwp_t *lwp = ttolwp(curthread);
60
61	/*
62	 * We assign to every field through uc_mcontext.fpregs.fpu_en,
63	 * but we have to bzero() everything after that.
64	 */
65	bzero(&ucp->uc_mcontext.fpregs.fpu_en, sizeof (ucontext_t) -
66	    offsetof(ucontext_t, uc_mcontext.fpregs.fpu_en));
67	/*
68	 * There are unused holes in the ucontext_t structure, zero-fill
69	 * them so that we don't expose kernel data to the user.
70	 */
71	(&ucp->uc_flags)[1] = 0;
72	(&ucp->uc_stack.ss_flags)[1] = 0;
73
74	/*
75	 * Flushing the user windows isn't strictly necessary; we do
76	 * it to maintain backward compatibility.
77	 */
78	(void) flush_user_windows_to_stack(NULL);
79
80	ucp->uc_flags = UC_ALL;
81	ucp->uc_link = (ucontext_t *)lwp->lwp_oldcontext;
82
83	/*
84	 * Try to copyin() the ustack if one is registered. If the stack
85	 * has zero size, this indicates that stack bounds checking has
86	 * been disabled for this LWP. If stack bounds checking is disabled
87	 * or the copyin() fails, we fall back to the legacy behavior.
88	 */
89	if (lwp->lwp_ustack == NULL ||
90	    copyin((void *)lwp->lwp_ustack, &ucp->uc_stack,
91	    sizeof (ucp->uc_stack)) != 0 ||
92	    ucp->uc_stack.ss_size == 0) {
93
94		if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) {
95			ucp->uc_stack = lwp->lwp_sigaltstack;
96		} else {
97			ucp->uc_stack.ss_sp = p->p_usrstack - p->p_stksize;
98			ucp->uc_stack.ss_size = p->p_stksize;
99			ucp->uc_stack.ss_flags = 0;
100		}
101	}
102
103	getgregs(lwp, ucp->uc_mcontext.gregs);
104	getasrs(lwp, ucp->uc_mcontext.asrs);
105
106	getfpregs(lwp, &ucp->uc_mcontext.fpregs);
107	getfpasrs(lwp, ucp->uc_mcontext.asrs);
108	if (ucp->uc_mcontext.fpregs.fpu_en == 0)
109		ucp->uc_flags &= ~UC_FPU;
110	ucp->uc_mcontext.gwins = (gwindows_t *)NULL;
111
112	/*
113	 * Save signal mask.
114	 */
115	sigktou(mask, &ucp->uc_sigmask);
116}
117
118
119void
120restorecontext(ucontext_t *ucp)
121{
122	kthread_t *t = curthread;
123	klwp_t *lwp = ttolwp(t);
124	mcontext_t *mcp = &ucp->uc_mcontext;
125	model_t model = lwp_getdatamodel(lwp);
126
127	(void) flush_user_windows_to_stack(NULL);
128	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE)
129		xregrestore(lwp, 0);
130
131	lwp->lwp_oldcontext = (uintptr_t)ucp->uc_link;
132
133	if (ucp->uc_flags & UC_STACK) {
134		if (ucp->uc_stack.ss_flags == SS_ONSTACK)
135			lwp->lwp_sigaltstack = ucp->uc_stack;
136		else
137			lwp->lwp_sigaltstack.ss_flags &= ~SS_ONSTACK;
138	}
139
140	if (ucp->uc_flags & UC_CPU) {
141		if (mcp->gwins != 0)
142			setgwins(lwp, mcp->gwins);
143		setgregs(lwp, mcp->gregs);
144		if (model == DATAMODEL_LP64)
145			setasrs(lwp, mcp->asrs);
146		else
147			xregs_setgregs(lwp, xregs_getptr(lwp, ucp));
148	}
149
150	if (ucp->uc_flags & UC_FPU) {
151		fpregset_t *fp = &ucp->uc_mcontext.fpregs;
152
153		setfpregs(lwp, fp);
154		if (model == DATAMODEL_LP64)
155			setfpasrs(lwp, mcp->asrs);
156		else
157			xregs_setfpregs(lwp, xregs_getptr(lwp, ucp));
158		run_fpq(lwp, fp);
159	}
160
161	if (ucp->uc_flags & UC_SIGMASK) {
162		/*
163		 * We don't need to acquire p->p_lock here;
164		 * we are manipulating thread-private data.
165		 */
166		schedctl_finish_sigblock(t);
167		sigutok(&ucp->uc_sigmask, &t->t_hold);
168		if (sigcheck(ttoproc(t), t))
169			t->t_sig_check = 1;
170	}
171}
172
173
174int
175getsetcontext(int flag, void *arg)
176{
177	ucontext_t uc;
178	struct fq fpu_q[MAXFPQ]; /* to hold floating queue */
179	fpregset_t *fpp;
180	gwindows_t *gwin = NULL;	/* to hold windows */
181	caddr_t xregs = NULL;
182	int xregs_size = 0;
183	extern int nwindows;
184	ucontext_t *ucp;
185	klwp_t *lwp = ttolwp(curthread);
186	stack_t dummy_stk;
187
188	/*
189	 * In future releases, when the ucontext structure grows,
190	 * getcontext should be modified to only return the fields
191	 * specified in the uc_flags.  That way, the structure can grow
192	 * and still be binary compatible will all .o's which will only
193	 * have old fields defined in uc_flags
194	 */
195
196	switch (flag) {
197	default:
198		return (set_errno(EINVAL));
199
200	case GETCONTEXT:
201		schedctl_finish_sigblock(curthread);
202		savecontext(&uc, &curthread->t_hold);
203		/*
204		 * When using floating point it should not be possible to
205		 * get here with a fpu_qcnt other than zero since we go
206		 * to great pains to handle all outstanding FP exceptions
207		 * before any system call code gets executed. However we
208		 * clear fpu_q and fpu_qcnt here before copyout anyway -
209		 * this will prevent us from interpreting the garbage we
210		 * get back (when FP is not enabled) as valid queue data on
211		 * a later setcontext(2).
212		 */
213		uc.uc_mcontext.fpregs.fpu_qcnt = 0;
214		uc.uc_mcontext.fpregs.fpu_q = (struct fq *)NULL;
215
216		if (copyout(&uc, arg, sizeof (ucontext_t)))
217			return (set_errno(EFAULT));
218		return (0);
219
220	case SETCONTEXT:
221		ucp = arg;
222		if (ucp == NULL)
223			exit(CLD_EXITED, 0);
224		/*
225		 * Don't copyin filler or floating state unless we need it.
226		 * The ucontext_t struct and fields are specified in the ABI.
227		 */
228		if (copyin(ucp, &uc, sizeof (ucontext_t) -
229		    sizeof (uc.uc_filler) -
230		    sizeof (uc.uc_mcontext.fpregs) -
231		    sizeof (uc.uc_mcontext.xrs) -
232		    sizeof (uc.uc_mcontext.asrs) -
233		    sizeof (uc.uc_mcontext.filler))) {
234			return (set_errno(EFAULT));
235		}
236		if (copyin(&ucp->uc_mcontext.xrs, &uc.uc_mcontext.xrs,
237		    sizeof (uc.uc_mcontext.xrs))) {
238			return (set_errno(EFAULT));
239		}
240		fpp = &uc.uc_mcontext.fpregs;
241		if (uc.uc_flags & UC_FPU) {
242			/*
243			 * Need to copyin floating point state
244			 */
245			if (copyin(&ucp->uc_mcontext.fpregs,
246			    &uc.uc_mcontext.fpregs,
247			    sizeof (uc.uc_mcontext.fpregs)))
248				return (set_errno(EFAULT));
249			/* if floating queue not empty */
250			if ((fpp->fpu_q) && (fpp->fpu_qcnt)) {
251				if (fpp->fpu_qcnt > MAXFPQ ||
252				    fpp->fpu_q_entrysize <= 0 ||
253				    fpp->fpu_q_entrysize > sizeof (struct fq))
254					return (set_errno(EINVAL));
255				if (copyin(fpp->fpu_q, fpu_q,
256				    fpp->fpu_qcnt * fpp->fpu_q_entrysize))
257					return (set_errno(EFAULT));
258				fpp->fpu_q = fpu_q;
259			} else {
260				fpp->fpu_qcnt = 0; /* avoid confusion later */
261			}
262		} else {
263			fpp->fpu_qcnt = 0;
264		}
265		if (uc.uc_mcontext.gwins) {	/* if windows in context */
266			size_t gwin_size;
267
268			/*
269			 * We do the same computation here to determine
270			 * how many bytes of gwindows_t to copy in that
271			 * is also done in sendsig() to decide how many
272			 * bytes to copy out.  We just *know* that wbcnt
273			 * is the first element of the structure.
274			 */
275			gwin = kmem_zalloc(sizeof (gwindows_t), KM_SLEEP);
276			if (copyin(uc.uc_mcontext.gwins,
277			    &gwin->wbcnt, sizeof (gwin->wbcnt))) {
278				kmem_free(gwin, sizeof (gwindows_t));
279				return (set_errno(EFAULT));
280			}
281			if (gwin->wbcnt < 0 || gwin->wbcnt > nwindows) {
282				kmem_free(gwin, sizeof (gwindows_t));
283				return (set_errno(EINVAL));
284			}
285			gwin_size = gwin->wbcnt * sizeof (struct rwindow) +
286			    SPARC_MAXREGWINDOW * sizeof (int *) + sizeof (long);
287			if (gwin_size > sizeof (gwindows_t) ||
288			    copyin(uc.uc_mcontext.gwins, gwin, gwin_size)) {
289				kmem_free(gwin, sizeof (gwindows_t));
290				return (set_errno(EFAULT));
291			}
292			uc.uc_mcontext.gwins = gwin;
293		}
294
295		/*
296		 * get extra register state or asrs if any exists
297		 * there is no extra register state for _LP64 user programs
298		 */
299		xregs_clrptr(lwp, &uc);
300		if (copyin(&ucp->uc_mcontext.asrs, &uc.uc_mcontext.asrs,
301		    sizeof (asrset_t))) {
302			/* Free up gwin structure if used */
303			if (gwin)
304				kmem_free(gwin, sizeof (gwindows_t));
305			return (set_errno(EFAULT));
306		}
307
308		restorecontext(&uc);
309
310		if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0)) {
311			(void) copyout(&uc.uc_stack, (stack_t *)lwp->lwp_ustack,
312			    sizeof (stack_t));
313		}
314
315		/*
316		 * free extra register state area
317		 */
318		if (xregs_size)
319			kmem_free(xregs, xregs_size);
320
321		if (gwin)
322			kmem_free(gwin, sizeof (gwindows_t));
323
324		return (0);
325
326	case GETUSTACK:
327		if (copyout(&lwp->lwp_ustack, arg, sizeof (caddr_t)))
328			return (set_errno(EFAULT));
329
330		return (0);
331
332	case SETUSTACK:
333		if (copyin(arg, &dummy_stk, sizeof (dummy_stk)))
334			return (set_errno(EFAULT));
335
336		lwp->lwp_ustack = (uintptr_t)arg;
337
338		return (0);
339	}
340}
341
342
343#ifdef _SYSCALL32_IMPL
344
345/*
346 * Save user context for 32-bit processes.
347 */
348void
349savecontext32(ucontext32_t *ucp, const k_sigset_t *mask, struct fq32 *dfq)
350{
351	proc_t *p = ttoproc(curthread);
352	klwp_t *lwp = ttolwp(curthread);
353	fpregset_t fpregs;
354
355	/*
356	 * We assign to every field through uc_mcontext.fpregs.fpu_en,
357	 * but we have to bzero() everything after that.
358	 */
359	bzero(&ucp->uc_mcontext.fpregs.fpu_en, sizeof (ucontext32_t) -
360	    offsetof(ucontext32_t, uc_mcontext.fpregs.fpu_en));
361	/*
362	 * There is an unused hole in the ucontext32_t structure; zero-fill
363	 * it so that we don't expose kernel data to the user.
364	 */
365	(&ucp->uc_stack.ss_flags)[1] = 0;
366
367	/*
368	 * Flushing the user windows isn't strictly necessary; we do
369	 * it to maintain backward compatibility.
370	 */
371	(void) flush_user_windows_to_stack(NULL);
372
373	ucp->uc_flags = UC_ALL;
374	ucp->uc_link = (caddr32_t)lwp->lwp_oldcontext;
375
376	/*
377	 * Try to copyin() the ustack if one is registered. If the stack
378	 * has zero size, this indicates that stack bounds checking has
379	 * been disabled for this LWP. If stack bounds checking is disabled
380	 * or the copyin() fails, we fall back to the legacy behavior.
381	 */
382	if (lwp->lwp_ustack == NULL ||
383	    copyin((void *)lwp->lwp_ustack, &ucp->uc_stack,
384	    sizeof (ucp->uc_stack)) != 0 ||
385	    ucp->uc_stack.ss_size == 0) {
386
387		if (lwp->lwp_sigaltstack.ss_flags == SS_ONSTACK) {
388			ucp->uc_stack.ss_sp =
389			    (caddr32_t)(uintptr_t)lwp->lwp_sigaltstack.ss_sp;
390			ucp->uc_stack.ss_size =
391			    (size32_t)lwp->lwp_sigaltstack.ss_size;
392			ucp->uc_stack.ss_flags = SS_ONSTACK;
393		} else {
394			ucp->uc_stack.ss_sp =
395			    (caddr32_t)(uintptr_t)p->p_usrstack - p->p_stksize;
396			ucp->uc_stack.ss_size =
397			    (size32_t)p->p_stksize;
398			ucp->uc_stack.ss_flags = 0;
399		}
400	}
401
402	getgregs32(lwp, ucp->uc_mcontext.gregs);
403	getfpregs(lwp, &fpregs);
404	fpuregset_nto32(&fpregs, &ucp->uc_mcontext.fpregs, dfq);
405
406	if (ucp->uc_mcontext.fpregs.fpu_en == 0)
407		ucp->uc_flags &= ~UC_FPU;
408	ucp->uc_mcontext.gwins = (caddr32_t)NULL;
409
410	/*
411	 * Save signal mask (the 32- and 64-bit sigset_t structures are
412	 * identical).
413	 */
414	sigktou(mask, (sigset_t *)&ucp->uc_sigmask);
415}
416
417int
418getsetcontext32(int flag, void *arg)
419{
420	ucontext32_t uc;
421	ucontext_t   ucnat;
422	struct fq fpu_qnat[MAXFPQ]; /* to hold "native" floating queue */
423	struct fq32 fpu_q[MAXFPQ]; /* to hold 32 bit floating queue */
424	fpregset32_t *fpp;
425	gwindows32_t *gwin = NULL;	/* to hold windows */
426	caddr_t xregs;
427	int xregs_size = 0;
428	extern int nwindows;
429	klwp_t *lwp = ttolwp(curthread);
430	ucontext32_t *ucp;
431	uint32_t ustack32;
432	stack32_t dummy_stk32;
433
434	/*
435	 * In future releases, when the ucontext structure grows,
436	 * getcontext should be modified to only return the fields
437	 * specified in the uc_flags.  That way, the structure can grow
438	 * and still be binary compatible will all .o's which will only
439	 * have old fields defined in uc_flags
440	 */
441
442	switch (flag) {
443	default:
444		return (set_errno(EINVAL));
445
446	case GETCONTEXT:
447		schedctl_finish_sigblock(curthread);
448		savecontext32(&uc, &curthread->t_hold, NULL);
449		/*
450		 * When using floating point it should not be possible to
451		 * get here with a fpu_qcnt other than zero since we go
452		 * to great pains to handle all outstanding FP exceptions
453		 * before any system call code gets executed. However we
454		 * clear fpu_q and fpu_qcnt here before copyout anyway -
455		 * this will prevent us from interpreting the garbage we
456		 * get back (when FP is not enabled) as valid queue data on
457		 * a later setcontext(2).
458		 */
459		uc.uc_mcontext.fpregs.fpu_qcnt = 0;
460		uc.uc_mcontext.fpregs.fpu_q = (caddr32_t)NULL;
461
462		if (copyout(&uc, arg, sizeof (ucontext32_t)))
463			return (set_errno(EFAULT));
464		return (0);
465
466	case SETCONTEXT:
467		ucp = arg;
468		if (ucp == NULL)
469			exit(CLD_EXITED, 0);
470		/*
471		 * Don't copyin filler or floating state unless we need it.
472		 * The ucontext_t struct and fields are specified in the ABI.
473		 */
474		if (copyin(ucp, &uc, sizeof (uc) - sizeof (uc.uc_filler) -
475		    sizeof (uc.uc_mcontext.fpregs) -
476		    sizeof (uc.uc_mcontext.xrs) -
477		    sizeof (uc.uc_mcontext.filler))) {
478			return (set_errno(EFAULT));
479		}
480		if (copyin(&ucp->uc_mcontext.xrs, &uc.uc_mcontext.xrs,
481		    sizeof (uc.uc_mcontext.xrs))) {
482			return (set_errno(EFAULT));
483		}
484		fpp = &uc.uc_mcontext.fpregs;
485		if (uc.uc_flags & UC_FPU) {
486			/*
487			 * Need to copyin floating point state
488			 */
489			if (copyin(&ucp->uc_mcontext.fpregs,
490			    &uc.uc_mcontext.fpregs,
491			    sizeof (uc.uc_mcontext.fpregs)))
492				return (set_errno(EFAULT));
493			/* if floating queue not empty */
494			if ((fpp->fpu_q) && (fpp->fpu_qcnt)) {
495				if (fpp->fpu_qcnt > MAXFPQ ||
496				    fpp->fpu_q_entrysize <= 0 ||
497				    fpp->fpu_q_entrysize > sizeof (struct fq32))
498					return (set_errno(EINVAL));
499				if (copyin((void *)(uintptr_t)fpp->fpu_q, fpu_q,
500				    fpp->fpu_qcnt * fpp->fpu_q_entrysize))
501					return (set_errno(EFAULT));
502			} else {
503				fpp->fpu_qcnt = 0; /* avoid confusion later */
504			}
505		} else {
506			fpp->fpu_qcnt = 0;
507		}
508
509		if (uc.uc_mcontext.gwins) {	/* if windows in context */
510			size_t gwin_size;
511
512			/*
513			 * We do the same computation here to determine
514			 * how many bytes of gwindows_t to copy in that
515			 * is also done in sendsig() to decide how many
516			 * bytes to copy out.  We just *know* that wbcnt
517			 * is the first element of the structure.
518			 */
519			gwin = kmem_zalloc(sizeof (gwindows32_t), KM_SLEEP);
520			if (copyin((void *)(uintptr_t)uc.uc_mcontext.gwins,
521			    &gwin->wbcnt, sizeof (gwin->wbcnt))) {
522				kmem_free(gwin, sizeof (gwindows32_t));
523				return (set_errno(EFAULT));
524			}
525			if (gwin->wbcnt < 0 || gwin->wbcnt > nwindows) {
526				kmem_free(gwin, sizeof (gwindows32_t));
527				return (set_errno(EINVAL));
528			}
529			gwin_size = gwin->wbcnt * sizeof (struct rwindow32) +
530			    SPARC_MAXREGWINDOW * sizeof (caddr32_t) +
531			    sizeof (int32_t);
532			if (gwin_size > sizeof (gwindows32_t) ||
533			    copyin((void *)(uintptr_t)uc.uc_mcontext.gwins,
534			    gwin, gwin_size)) {
535				kmem_free(gwin, sizeof (gwindows32_t));
536				return (set_errno(EFAULT));
537			}
538			/* restorecontext() should ignore this */
539			uc.uc_mcontext.gwins = (caddr32_t)0;
540		}
541
542		ucontext_32ton(&uc, &ucnat, fpu_q, fpu_qnat);
543
544		/*
545		 * get extra register state if any exists
546		 */
547		if (xregs_hasptr32(lwp, &uc) &&
548		    ((xregs_size = xregs_getsize(curproc)) > 0)) {
549			xregs = kmem_zalloc(xregs_size, KM_SLEEP);
550			if (copyin((void *)(uintptr_t)xregs_getptr32(lwp, &uc),
551			    xregs, xregs_size)) {
552				kmem_free(xregs, xregs_size);
553				if (gwin)
554					kmem_free(gwin, sizeof (gwindows32_t));
555				return (set_errno(EFAULT));
556			}
557			xregs_setptr(lwp, &ucnat, xregs);
558		} else {
559			xregs_clrptr(lwp, &ucnat);
560		}
561
562		restorecontext(&ucnat);
563
564		if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0)) {
565			(void) copyout(&uc.uc_stack,
566			    (stack32_t *)lwp->lwp_ustack, sizeof (stack32_t));
567		}
568
569		if (gwin)
570			setgwins32(lwp, gwin);
571
572		/*
573		 * free extra register state area
574		 */
575		if (xregs_size)
576			kmem_free(xregs, xregs_size);
577
578		if (gwin)
579			kmem_free(gwin, sizeof (gwindows32_t));
580
581		return (0);
582
583	case GETUSTACK:
584		ustack32 = (uint32_t)lwp->lwp_ustack;
585		if (copyout(&ustack32, arg, sizeof (caddr32_t)))
586			return (set_errno(EFAULT));
587
588		return (0);
589
590	case SETUSTACK:
591		if (copyin(arg, &dummy_stk32, sizeof (dummy_stk32)))
592			return (set_errno(EFAULT));
593
594		lwp->lwp_ustack = (uintptr_t)arg;
595
596		return (0);
597	}
598}
599
600#endif	/* _SYSCALL32_IMPL */
601