xref: /illumos-gate/usr/src/lib/libc/sparc/gen/makectxt.c (revision 7257d1b4d25bfac0c802847390e98a464fd787ac)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1988 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #pragma weak _makecontext = makecontext
33 #pragma weak ___makecontext_v2 = __makecontext_v2
34 
35 #include "lint.h"
36 #include <stdarg.h>
37 #include <strings.h>
38 #include <sys/ucontext.h>
39 #include <sys/stack.h>
40 #include <sys/frame.h>
41 
42 /*
43  * The ucontext_t that the user passes in must have been primed with a
44  * call to getcontext(2), have the uc_stack member set to reflect the
45  * stack which this context will use, and have the uc_link member set
46  * to the context which should be resumed when this context returns.
47  * When makecontext() returns, the ucontext_t will be set to run the
48  * given function with the given parameters on the stack specified by
49  * uc_stack, and which will return to the ucontext_t specified by uc_link.
50  */
51 
52 static void resumecontext(void);
53 
54 void
55 makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
56 {
57 	greg_t *reg;
58 	long *tsp;
59 	char *sp;
60 	int argno;
61 	va_list ap;
62 	size_t size;
63 
64 	reg = ucp->uc_mcontext.gregs;
65 	reg[REG_PC] = (greg_t)func;
66 	reg[REG_nPC] = reg[REG_PC] + 0x4;
67 
68 	/*
69 	 * Reserve enough space for a frame and the arguments beyond the
70 	 * sixth; round to stack alignment.
71 	 */
72 	size = sizeof (struct frame);
73 	size += (argc > 6 ? argc - 6 : 0) * sizeof (long);
74 
75 	/*
76 	 * The legacy implemenation of makecontext() on sparc has been to
77 	 * interpret the uc_stack.ss_sp member incorrectly as the top of the
78 	 * stack rather than the base. We preserve this behavior here, but
79 	 * provide the correct semantics in __makecontext_v2().
80 	 */
81 	sp = (char *)(((uintptr_t)ucp->uc_stack.ss_sp - size) &
82 	    ~(STACK_ALIGN - 1));
83 
84 	/*
85 	 * Copy all args to the stack, and put the first 6 args into the
86 	 * ucontext_t. Zero the other fields of the frame.
87 	 */
88 	/* LINTED pointer cast may result in improper alignment */
89 	tsp = &((struct frame *)sp)->fr_argd[0];
90 	bzero(sp, sizeof (struct frame));
91 
92 	va_start(ap, argc);
93 
94 	for (argno = 0; argno < argc; argno++) {
95 		if (argno < 6)
96 			*tsp++ = reg[REG_O0 + argno] = va_arg(ap, long);
97 		else
98 			*tsp++ = va_arg(ap, long);
99 	}
100 
101 	va_end(ap);
102 
103 	reg[REG_SP] = (greg_t)sp - STACK_BIAS;		/* sp (when done) */
104 	reg[REG_O7] = (greg_t)resumecontext - 8;	/* return pc */
105 }
106 
107 void
108 __makecontext_v2(ucontext_t *ucp, void (*func)(), int argc, ...)
109 {
110 	greg_t *reg;
111 	long *tsp;
112 	char *sp;
113 	int argno;
114 	va_list ap;
115 	size_t size;
116 
117 	reg = ucp->uc_mcontext.gregs;
118 	reg[REG_PC] = (greg_t)func;
119 	reg[REG_nPC] = reg[REG_PC] + 0x4;
120 
121 	/*
122 	 * Reserve enough space for a frame and the arguments beyond the
123 	 * sixth; round to stack alignment.
124 	 */
125 	size = sizeof (struct frame);
126 	size += (argc > 6 ? argc - 6 : 0) * sizeof (long);
127 
128 	sp = (char *)(((uintptr_t)ucp->uc_stack.ss_sp +
129 	    ucp->uc_stack.ss_size - size) & ~(STACK_ALIGN - 1));
130 
131 	/*
132 	 * Copy all args to the stack, and put the first 6 args into the
133 	 * ucontext_t. Zero the other fields of the frame.
134 	 */
135 	/* LINTED pointer cast may result in improper alignment */
136 	tsp = &((struct frame *)sp)->fr_argd[0];
137 	bzero(sp, sizeof (struct frame));
138 
139 	va_start(ap, argc);
140 
141 	for (argno = 0; argno < argc; argno++) {
142 		if (argno < 6)
143 			*tsp++ = reg[REG_O0 + argno] = va_arg(ap, long);
144 		else
145 			*tsp++ = va_arg(ap, long);
146 	}
147 
148 	va_end(ap);
149 
150 	reg[REG_SP] = (greg_t)sp - STACK_BIAS;		/* sp (when done) */
151 	reg[REG_O7] = (greg_t)resumecontext - 8;	/* return pc */
152 }
153 
154 static void
155 resumecontext(void)
156 {
157 	/*
158 	 * We can't include ucontext.h (where these functions are defined)
159 	 * because it remaps the symbol makecontext.
160 	 */
161 	extern int getcontext(ucontext_t *);
162 	extern int setcontext(const ucontext_t *);
163 	ucontext_t uc;
164 
165 	(void) getcontext(&uc);
166 	(void) setcontext(uc.uc_link);
167 }
168