xref: /trueos/lib/libkse/arch/amd64/include/pthread_md.h (revision f1ac56b04d023087e7771958a39880cb905293e9)
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