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