xref: /illumos-gate/usr/src/lib/libc/i386/threads/machdep.c (revision ae115bc77f6fcde83175c75b4206dc2e50747966)
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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include "thr_uberdata.h"
29 #include <procfs.h>
30 #include <ucontext.h>
31 #include <setjmp.h>
32 
33 extern int getlwpstatus(thread_t, lwpstatus_t *);
34 extern int putlwpregs(thread_t, prgregset_t);
35 
36 int
37 setup_context(ucontext_t *ucp, void *(*func)(ulwp_t *),
38 	ulwp_t *ulwp, caddr_t stk, size_t stksize)
39 {
40 	static int initialized;
41 	static greg_t fs, es, ds, cs, ss;
42 
43 	uint32_t *stack;
44 
45 	if (!initialized) {
46 		ucontext_t uc;
47 
48 		/* do this once to load the segment registers */
49 		uc.uc_flags = UC_CPU;
50 		(void) __getcontext_syscall(&uc);
51 		fs = uc.uc_mcontext.gregs[FS];
52 		es = uc.uc_mcontext.gregs[ES];
53 		ds = uc.uc_mcontext.gregs[DS];
54 		cs = uc.uc_mcontext.gregs[CS];
55 		ss = uc.uc_mcontext.gregs[SS];
56 		initialized = 1;
57 	}
58 	/* clear the context and set the segment registers */
59 	(void) _memset(ucp, 0, sizeof (*ucp));
60 	ucp->uc_mcontext.gregs[FS] = fs;
61 	ucp->uc_mcontext.gregs[ES] = es;
62 	ucp->uc_mcontext.gregs[DS] = ds;
63 	ucp->uc_mcontext.gregs[CS] = cs;
64 	ucp->uc_mcontext.gregs[SS] = ss;
65 
66 	/*
67 	 * Yuck.
68 	 * Use unused kernel pointer field in ucontext
69 	 * to pass down self pointer and set %gs selector
70 	 * value so __lwp_create() can setup %gs atomically.
71 	 * Without this we would need to block all signals
72 	 * and directly call __lwp_setprivate() in _thr_setup
73 	 * on the other side of __lwp_create().
74 	 */
75 	ucp->uc_mcontext.gregs[ESP] = (greg_t)ulwp;
76 	ucp->uc_mcontext.gregs[GS] = (greg_t)LWPGS_SEL;
77 
78 	/* top-of-stack must be rounded down to STACK_ALIGN */
79 	stack = (uint32_t *)(((uintptr_t)stk + stksize) & ~(STACK_ALIGN-1));
80 
81 	/* set up top stack frame */
82 	*--stack = 0;
83 	*--stack = 0;
84 	*--stack = (uint32_t)ulwp;
85 	*--stack = (uint32_t)_lwp_start;
86 
87 	/* fill in registers of interest */
88 	ucp->uc_flags |= UC_CPU;
89 	ucp->uc_mcontext.gregs[EIP] = (greg_t)func;
90 	ucp->uc_mcontext.gregs[UESP] = (greg_t)stack;
91 	ucp->uc_mcontext.gregs[EBP] = (greg_t)(stack+2);
92 
93 	return (0);
94 }
95 
96 /*
97  * Machine-dependent startup code for a newly-created thread.
98  */
99 void *
100 _thr_setup(ulwp_t *self)
101 {
102 	self->ul_ustack.ss_sp = (void *)(self->ul_stktop - self->ul_stksiz);
103 	self->ul_ustack.ss_size = self->ul_stksiz;
104 	self->ul_ustack.ss_flags = 0;
105 	(void) _private_setustack(&self->ul_ustack);
106 
107 	tls_setup();
108 
109 	/* signals have been deferred until now */
110 	sigon(self);
111 
112 	return (self->ul_startpc(self->ul_startarg));
113 }
114 
115 void
116 _fpinherit(ulwp_t *ulwp)
117 {
118 	ulwp->ul_fpuenv.ftag = 0xffffffff;
119 }
120 
121 void
122 getgregs(ulwp_t *ulwp, gregset_t rs)
123 {
124 	lwpstatus_t status;
125 
126 	if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) {
127 		rs[EIP] = status.pr_reg[EIP];
128 		rs[EDI] = status.pr_reg[EDI];
129 		rs[ESI] = status.pr_reg[ESI];
130 		rs[EBP] = status.pr_reg[EBP];
131 		rs[EBX] = status.pr_reg[EBX];
132 		rs[UESP] = status.pr_reg[UESP];
133 	} else {
134 		rs[EIP] = 0;
135 		rs[EDI] = 0;
136 		rs[ESI] = 0;
137 		rs[EBP] = 0;
138 		rs[EBX] = 0;
139 		rs[UESP] = 0;
140 	}
141 }
142 
143 void
144 setgregs(ulwp_t *ulwp, gregset_t rs)
145 {
146 	lwpstatus_t status;
147 
148 	if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) {
149 		status.pr_reg[EIP] = rs[EIP];
150 		status.pr_reg[EDI] = rs[EDI];
151 		status.pr_reg[ESI] = rs[ESI];
152 		status.pr_reg[EBP] = rs[EBP];
153 		status.pr_reg[EBX] = rs[EBX];
154 		status.pr_reg[UESP] = rs[UESP];
155 		(void) putlwpregs(ulwp->ul_lwpid, status.pr_reg);
156 	}
157 }
158 
159 int
160 __csigsetjmp(greg_t cs, greg_t ss, greg_t gs,
161 	greg_t fs, greg_t es, greg_t ds,
162 	greg_t edi, greg_t esi, greg_t ebp, greg_t esp,
163 	greg_t ebx, greg_t edx, greg_t ecx, greg_t eax, greg_t eip,
164 	sigjmp_buf env, int savemask)
165 {
166 	ucontext_t *ucp = (ucontext_t *)env;
167 	ulwp_t *self = curthread;
168 
169 	ucp->uc_link = self->ul_siglink;
170 	if (self->ul_ustack.ss_flags & SS_ONSTACK)
171 		ucp->uc_stack = self->ul_ustack;
172 	else {
173 		ucp->uc_stack.ss_sp =
174 			(void *)(self->ul_stktop - self->ul_stksiz);
175 		ucp->uc_stack.ss_size = self->ul_stksiz;
176 		ucp->uc_stack.ss_flags = 0;
177 	}
178 	ucp->uc_flags = UC_STACK | UC_CPU;
179 	if (savemask) {
180 		ucp->uc_flags |= UC_SIGMASK;
181 		enter_critical(self);
182 		ucp->uc_sigmask = self->ul_sigmask;
183 		exit_critical(self);
184 	}
185 	ucp->uc_mcontext.gregs[GS] = gs;
186 	ucp->uc_mcontext.gregs[FS] = fs;
187 	ucp->uc_mcontext.gregs[ES] = es;
188 	ucp->uc_mcontext.gregs[DS] = ds;
189 	ucp->uc_mcontext.gregs[EDI] = edi;
190 	ucp->uc_mcontext.gregs[ESI] = esi;
191 	ucp->uc_mcontext.gregs[EBP] = ebp;
192 	ucp->uc_mcontext.gregs[ESP] = esp + 4;
193 	ucp->uc_mcontext.gregs[EBX] = ebx;
194 	ucp->uc_mcontext.gregs[EDX] = edx;
195 	ucp->uc_mcontext.gregs[ECX] = ecx;
196 	ucp->uc_mcontext.gregs[EAX] = eax;
197 	ucp->uc_mcontext.gregs[TRAPNO] = 0;
198 	ucp->uc_mcontext.gregs[ERR] = 0;
199 	ucp->uc_mcontext.gregs[EIP] = eip;
200 	ucp->uc_mcontext.gregs[CS] = cs;
201 	ucp->uc_mcontext.gregs[EFL] = 0;
202 	ucp->uc_mcontext.gregs[UESP] = esp + 4;
203 	ucp->uc_mcontext.gregs[SS] = ss;
204 
205 	return (0);
206 }
207