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