1 /*-
2 * Copyright (C) 2003 David Xu <davidxu@freebsd.org>
3 * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Neither the name of the author nor the names of its contributors
12 * may be used to endorse or promote products derived from this software
13 * without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD$
28 */
29 /*
30 * Machine-dependent thread prototypes/definitions for the thread kernel.
31 */
32 #ifndef _PTHREAD_MD_H_
33 #define _PTHREAD_MD_H_
34
35 #include <stddef.h>
36 #include <sys/types.h>
37 #include <sys/kse.h>
38 #include <machine/sysarch.h>
39 #include <ucontext.h>
40
41 #define KSE_STACKSIZE 16384
42 #define DTV_OFFSET offsetof(struct tcb, tcb_dtv)
43
44 #define THR_GETCONTEXT(ucp) \
45 (void)_amd64_save_context(&(ucp)->uc_mcontext)
46 #define THR_SETCONTEXT(ucp) \
47 (void)_amd64_restore_context(&(ucp)->uc_mcontext, 0, NULL)
48
49 #define PER_KSE
50 #undef PER_THREAD
51
52 struct kse;
53 struct pthread;
54 struct tdv;
55
56 /*
57 * %fs points to a struct kcb.
58 */
59 struct kcb {
60 struct tcb *kcb_curtcb;
61 struct kcb *kcb_self; /* self reference */
62 struct kse *kcb_kse;
63 struct kse_mailbox kcb_kmbx;
64 };
65
66 struct tcb {
67 struct tcb *tcb_self; /* required by rtld */
68 void *tcb_dtv; /* required by rtld */
69 struct pthread *tcb_thread;
70 void *tcb_spare[1]; /* align tcb_tmbx to 16 bytes */
71 struct kse_thr_mailbox tcb_tmbx;
72 };
73
74 /*
75 * Evaluates to the byte offset of the per-kse variable name.
76 */
77 #define __kcb_offset(name) __offsetof(struct kcb, name)
78
79 /*
80 * Evaluates to the type of the per-kse variable name.
81 */
82 #define __kcb_type(name) __typeof(((struct kcb *)0)->name)
83
84 /*
85 * Evaluates to the value of the per-kse variable name.
86 */
87 #define KCB_GET64(name) ({ \
88 __kcb_type(name) __result; \
89 \
90 u_long __i; \
91 __asm __volatile("movq %%fs:%1, %0" \
92 : "=r" (__i) \
93 : "m" (*(u_long *)(__kcb_offset(name)))); \
94 __result = (__kcb_type(name))__i; \
95 \
96 __result; \
97 })
98
99 /*
100 * Sets the value of the per-kse variable name to value val.
101 */
102 #define KCB_SET64(name, val) ({ \
103 __kcb_type(name) __val = (val); \
104 \
105 u_long __i; \
106 __i = (u_long)__val; \
107 __asm __volatile("movq %1,%%fs:%0" \
108 : "=m" (*(u_long *)(__kcb_offset(name))) \
109 : "r" (__i)); \
110 })
111
112 static __inline u_long
__kcb_readandclear64(volatile u_long * addr)113 __kcb_readandclear64(volatile u_long *addr)
114 {
115 u_long result;
116
117 __asm __volatile (
118 " xorq %0, %0;"
119 " xchgq %%fs:%1, %0;"
120 "# __kcb_readandclear64"
121 : "=&r" (result)
122 : "m" (*addr));
123 return (result);
124 }
125
126 #define KCB_READANDCLEAR64(name) ({ \
127 __kcb_type(name) __result; \
128 \
129 __result = (__kcb_type(name)) \
130 __kcb_readandclear64((u_long *)__kcb_offset(name)); \
131 __result; \
132 })
133
134
135 #define _kcb_curkcb() KCB_GET64(kcb_self)
136 #define _kcb_curtcb() KCB_GET64(kcb_curtcb)
137 #define _kcb_curkse() ((struct kse *)KCB_GET64(kcb_kmbx.km_udata))
138 #define _kcb_get_tmbx() KCB_GET64(kcb_kmbx.km_curthread)
139 #define _kcb_set_tmbx(value) KCB_SET64(kcb_kmbx.km_curthread, (void *)value)
140 #define _kcb_readandclear_tmbx() KCB_READANDCLEAR64(kcb_kmbx.km_curthread)
141
142 /*
143 * The constructors.
144 */
145 struct tcb *_tcb_ctor(struct pthread *, int);
146 void _tcb_dtor(struct tcb *tcb);
147 struct kcb *_kcb_ctor(struct kse *);
148 void _kcb_dtor(struct kcb *);
149
150 /* Called from the KSE to set its private data. */
151 static __inline void
_kcb_set(struct kcb * kcb)152 _kcb_set(struct kcb *kcb)
153 {
154 amd64_set_fsbase(kcb);
155 }
156
157 /* Get the current kcb. */
158 static __inline struct kcb *
_kcb_get(void)159 _kcb_get(void)
160 {
161 return (_kcb_curkcb());
162 }
163
164 static __inline struct kse_thr_mailbox *
_kcb_critical_enter(void)165 _kcb_critical_enter(void)
166 {
167 struct kse_thr_mailbox *crit;
168
169 crit = _kcb_readandclear_tmbx();
170 return (crit);
171 }
172
173 static __inline void
_kcb_critical_leave(struct kse_thr_mailbox * crit)174 _kcb_critical_leave(struct kse_thr_mailbox *crit)
175 {
176 _kcb_set_tmbx(crit);
177 }
178
179 static __inline int
_kcb_in_critical(void)180 _kcb_in_critical(void)
181 {
182 return (_kcb_get_tmbx() == NULL);
183 }
184
185 static __inline void
_tcb_set(struct kcb * kcb,struct tcb * tcb)186 _tcb_set(struct kcb *kcb, struct tcb *tcb)
187 {
188 kcb->kcb_curtcb = tcb;
189 }
190
191 static __inline struct tcb *
_tcb_get(void)192 _tcb_get(void)
193 {
194 return (_kcb_curtcb());
195 }
196
197 static __inline struct pthread *
_get_curthread(void)198 _get_curthread(void)
199 {
200 struct tcb *tcb;
201
202 tcb = _kcb_curtcb();
203 if (tcb != NULL)
204 return (tcb->tcb_thread);
205 else
206 return (NULL);
207 }
208
209 static __inline struct kse *
_get_curkse(void)210 _get_curkse(void)
211 {
212 return ((struct kse *)_kcb_curkse());
213 }
214
215 void _amd64_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
216 size_t stacksz);
217 int _amd64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc);
218 int _amd64_save_context(mcontext_t *mc);
219
220 static __inline int
_thread_enter_uts(struct tcb * tcb,struct kcb * kcb)221 _thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
222 {
223 int ret;
224
225 ret = _amd64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext);
226 if (ret == 0) {
227 _amd64_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
228 kcb->kcb_kmbx.km_stack.ss_sp,
229 kcb->kcb_kmbx.km_stack.ss_size);
230 /* We should not reach here. */
231 return (-1);
232 }
233 else if (ret < 0)
234 return (-1);
235 return (0);
236 }
237
238 static __inline int
_thread_switch(struct kcb * kcb,struct tcb * tcb,int setmbox)239 _thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
240 {
241 extern int _libkse_debug;
242
243 if ((kcb == NULL) || (tcb == NULL))
244 return (-1);
245 kcb->kcb_curtcb = tcb;
246
247 if (_libkse_debug == 0) {
248 tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
249 if (setmbox != 0)
250 _amd64_restore_context(
251 &tcb->tcb_tmbx.tm_context.uc_mcontext,
252 (intptr_t)&tcb->tcb_tmbx,
253 (intptr_t *)(void *)&kcb->kcb_kmbx.km_curthread);
254 else
255 _amd64_restore_context(
256 &tcb->tcb_tmbx.tm_context.uc_mcontext,
257 0, NULL);
258 /* We should not reach here. */
259 } else {
260 if (setmbox)
261 kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
262 else
263 kse_switchin(&tcb->tcb_tmbx, 0);
264 }
265
266 return (-1);
267 }
268 #endif
269