xref: /illumos-gate/usr/src/lib/libc/i386/threads/machdep.c (revision 373d25a2f31a841db3ccd7bd0a8102efeb2df54f)
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 #include "thr_uberdata.h"
28 #include <procfs.h>
29 #include <ucontext.h>
30 #include <setjmp.h>
31 
32 extern int getlwpstatus(thread_t, lwpstatus_t *);
33 extern int putlwpregs(thread_t, prgregset_t);
34 
35 void *
36 setup_top_frame(void *stk, size_t stksize, ulwp_t *ulwp)
37 {
38 	uint32_t *stack;
39 	struct {
40 		uint32_t	rpc;
41 		uint32_t	arg;
42 		uint32_t	fp;
43 		uint32_t	pc;
44 	} frame;
45 
46 	/*
47 	 * Top-of-stack must be rounded down to STACK_ALIGN and
48 	 * there must be a minimum frame.
49 	 */
50 	stack = (uint32_t *)(((uintptr_t)stk + stksize) & ~(STACK_ALIGN-1));
51 
52 	/*
53 	 * This will return NULL if the kernel cannot allocate
54 	 * a page for the top page of the stack.  This will cause
55 	 * thr_create(), pthread_create() or pthread_attr_setstack()
56 	 * to fail, passing the problem up to the application.
57 	 */
58 	stack -= 4;
59 	frame.pc = 0;
60 	frame.fp = 0;
61 	frame.arg = (uint32_t)ulwp;
62 	frame.rpc = (uint32_t)_lwp_start;
63 	if (uucopy(&frame, (void *)stack, sizeof (frame)) == 0)
64 		return (stack);
65 	return (NULL);
66 }
67 
68 int
69 setup_context(ucontext_t *ucp, void *(*func)(ulwp_t *),
70 	ulwp_t *ulwp, caddr_t stk, size_t stksize)
71 {
72 	static int initialized;
73 	static greg_t fs, es, ds, cs, ss;
74 
75 	uint32_t *stack;
76 
77 	if (!initialized) {
78 		ucontext_t uc;
79 
80 		/* do this once to load the segment registers */
81 		uc.uc_flags = UC_CPU;
82 		(void) __getcontext(&uc);
83 		fs = uc.uc_mcontext.gregs[FS];
84 		es = uc.uc_mcontext.gregs[ES];
85 		ds = uc.uc_mcontext.gregs[DS];
86 		cs = uc.uc_mcontext.gregs[CS];
87 		ss = uc.uc_mcontext.gregs[SS];
88 		initialized = 1;
89 	}
90 	/* clear the context and set the segment registers */
91 	(void) memset(ucp, 0, sizeof (*ucp));
92 	ucp->uc_mcontext.gregs[FS] = fs;
93 	ucp->uc_mcontext.gregs[ES] = es;
94 	ucp->uc_mcontext.gregs[DS] = ds;
95 	ucp->uc_mcontext.gregs[CS] = cs;
96 	ucp->uc_mcontext.gregs[SS] = ss;
97 
98 	/*
99 	 * Yuck.
100 	 * Use unused kernel pointer field in ucontext
101 	 * to pass down self pointer and set %gs selector
102 	 * value so __lwp_create() can setup %gs atomically.
103 	 * Without this we would need to block all signals
104 	 * and directly call ___lwp_private() in _thrp_setup
105 	 * on the other side of __lwp_create().
106 	 */
107 	ucp->uc_mcontext.gregs[ESP] = (greg_t)ulwp;
108 	ucp->uc_mcontext.gregs[GS] = (greg_t)LWPGS_SEL;
109 
110 	/*
111 	 * Setup the top stack frame.
112 	 * If this fails, pass the problem up to the application.
113 	 */
114 	if ((stack = setup_top_frame(stk, stksize, ulwp)) == NULL)
115 		return (ENOMEM);
116 
117 	/* fill in registers of interest */
118 	ucp->uc_flags |= UC_CPU;
119 	ucp->uc_mcontext.gregs[EIP] = (greg_t)func;
120 	ucp->uc_mcontext.gregs[UESP] = (greg_t)stack;
121 	ucp->uc_mcontext.gregs[EBP] = (greg_t)(stack + 2);
122 
123 	return (0);
124 }
125 
126 /*
127  * Machine-dependent startup code for a newly-created thread.
128  */
129 void *
130 _thrp_setup(ulwp_t *self)
131 {
132 	self->ul_ustack.ss_sp = (void *)(self->ul_stktop - self->ul_stksiz);
133 	self->ul_ustack.ss_size = self->ul_stksiz;
134 	self->ul_ustack.ss_flags = 0;
135 	(void) setustack(&self->ul_ustack);
136 
137 	update_sched(self);
138 	tls_setup();
139 
140 	/* signals have been deferred until now */
141 	sigon(self);
142 
143 	if (self->ul_cancel_pending == 2 && !self->ul_cancel_disabled)
144 		return (NULL);	/* cancelled by pthread_create() */
145 	return (self->ul_startpc(self->ul_startarg));
146 }
147 
148 void
149 _fpinherit(ulwp_t *ulwp)
150 {
151 	ulwp->ul_fpuenv.ftag = 0xffffffff;
152 }
153 
154 void
155 getgregs(ulwp_t *ulwp, gregset_t rs)
156 {
157 	lwpstatus_t status;
158 
159 	if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) {
160 		rs[EIP] = status.pr_reg[EIP];
161 		rs[EDI] = status.pr_reg[EDI];
162 		rs[ESI] = status.pr_reg[ESI];
163 		rs[EBP] = status.pr_reg[EBP];
164 		rs[EBX] = status.pr_reg[EBX];
165 		rs[UESP] = status.pr_reg[UESP];
166 	} else {
167 		rs[EIP] = 0;
168 		rs[EDI] = 0;
169 		rs[ESI] = 0;
170 		rs[EBP] = 0;
171 		rs[EBX] = 0;
172 		rs[UESP] = 0;
173 	}
174 }
175 
176 void
177 setgregs(ulwp_t *ulwp, gregset_t rs)
178 {
179 	lwpstatus_t status;
180 
181 	if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) {
182 		status.pr_reg[EIP] = rs[EIP];
183 		status.pr_reg[EDI] = rs[EDI];
184 		status.pr_reg[ESI] = rs[ESI];
185 		status.pr_reg[EBP] = rs[EBP];
186 		status.pr_reg[EBX] = rs[EBX];
187 		status.pr_reg[UESP] = rs[UESP];
188 		(void) putlwpregs(ulwp->ul_lwpid, status.pr_reg);
189 	}
190 }
191 
192 int
193 __csigsetjmp(greg_t cs, greg_t ss, greg_t gs,
194 	greg_t fs, greg_t es, greg_t ds,
195 	greg_t edi, greg_t esi, greg_t ebp, greg_t esp,
196 	greg_t ebx, greg_t edx, greg_t ecx, greg_t eax, greg_t eip,
197 	sigjmp_buf env, int savemask)
198 {
199 	ucontext_t *ucp = (ucontext_t *)env;
200 	ulwp_t *self = curthread;
201 
202 	ucp->uc_link = self->ul_siglink;
203 	if (self->ul_ustack.ss_flags & SS_ONSTACK)
204 		ucp->uc_stack = self->ul_ustack;
205 	else {
206 		ucp->uc_stack.ss_sp =
207 		    (void *)(self->ul_stktop - self->ul_stksiz);
208 		ucp->uc_stack.ss_size = self->ul_stksiz;
209 		ucp->uc_stack.ss_flags = 0;
210 	}
211 	ucp->uc_flags = UC_STACK | UC_CPU;
212 	if (savemask) {
213 		ucp->uc_flags |= UC_SIGMASK;
214 		enter_critical(self);
215 		ucp->uc_sigmask = self->ul_sigmask;
216 		exit_critical(self);
217 	}
218 	ucp->uc_mcontext.gregs[GS] = gs;
219 	ucp->uc_mcontext.gregs[FS] = fs;
220 	ucp->uc_mcontext.gregs[ES] = es;
221 	ucp->uc_mcontext.gregs[DS] = ds;
222 	ucp->uc_mcontext.gregs[EDI] = edi;
223 	ucp->uc_mcontext.gregs[ESI] = esi;
224 	ucp->uc_mcontext.gregs[EBP] = ebp;
225 	ucp->uc_mcontext.gregs[ESP] = esp + 4;
226 	ucp->uc_mcontext.gregs[EBX] = ebx;
227 	ucp->uc_mcontext.gregs[EDX] = edx;
228 	ucp->uc_mcontext.gregs[ECX] = ecx;
229 	ucp->uc_mcontext.gregs[EAX] = eax;
230 	ucp->uc_mcontext.gregs[TRAPNO] = 0;
231 	ucp->uc_mcontext.gregs[ERR] = 0;
232 	ucp->uc_mcontext.gregs[EIP] = eip;
233 	ucp->uc_mcontext.gregs[CS] = cs;
234 	ucp->uc_mcontext.gregs[EFL] = 0;
235 	ucp->uc_mcontext.gregs[UESP] = esp + 4;
236 	ucp->uc_mcontext.gregs[SS] = ss;
237 
238 	return (0);
239 }
240