1113656Sdeischen/*-
2113656Sdeischen * Copyright (c) 2002 Daniel Eischen <deischen@freebsd.org>.
3113656Sdeischen * All rights reserved.
4113656Sdeischen *
5113656Sdeischen * Redistribution and use in source and binary forms, with or without
6113656Sdeischen * modification, are permitted provided that the following conditions
7113656Sdeischen * are met:
8113656Sdeischen * 1. Redistributions of source code must retain the above copyright
9113656Sdeischen *    notice, this list of conditions and the following disclaimer.
10113656Sdeischen * 2. Redistributions in binary form must reproduce the above copyright
11113656Sdeischen *    notice, this list of conditions and the following disclaimer in the
12113656Sdeischen *    documentation and/or other materials provided with the distribution.
13113656Sdeischen *
14113656Sdeischen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15113656Sdeischen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16113656Sdeischen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17113656Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18113656Sdeischen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19113656Sdeischen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20113656Sdeischen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21113656Sdeischen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22113656Sdeischen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23113656Sdeischen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24113656Sdeischen * SUCH DAMAGE.
25113656Sdeischen *
26113656Sdeischen * $FreeBSD$
27113656Sdeischen */
28113656Sdeischen/*
29113656Sdeischen * Machine-dependent thread prototypes/definitions for the thread kernel.
30113656Sdeischen */
31113656Sdeischen#ifndef _PTHREAD_MD_H_
32113656Sdeischen#define	_PTHREAD_MD_H_
33113656Sdeischen
34133801Sdavidxu#include <stddef.h>
35137295Speter#include <sys/types.h>
36118277Sdeischen#include <sys/kse.h>
37137295Speter#include <machine/sysarch.h>
38113656Sdeischen#include <ucontext.h>
39113656Sdeischen
40118277Sdeischenextern int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
41118277Sdeischenextern int _thr_getcontext(mcontext_t *);
42113656Sdeischen
43120263Smarcel#define	KSE_STACKSIZE		16384
44133801Sdavidxu#define	DTV_OFFSET		offsetof(struct tcb, tcb_dtv)
45120263Smarcel
46118510Sdeischen#define	THR_GETCONTEXT(ucp)	_thr_getcontext(&(ucp)->uc_mcontext)
47118510Sdeischen#define	THR_SETCONTEXT(ucp)	_thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
48113656Sdeischen
49118510Sdeischen#define	PER_KSE
50118510Sdeischen#undef	PER_THREAD
51116771Smarcel
52118510Sdeischenstruct kse;
53118510Sdeischenstruct pthread;
54118510Sdeischen
55116771Smarcel/*
56118510Sdeischen * %gs points to a struct kcb.
57116771Smarcel */
58118510Sdeischenstruct kcb {
59118510Sdeischen	struct tcb		*kcb_curtcb;
60118510Sdeischen	struct kcb		*kcb_self;	/* self reference */
61118510Sdeischen	struct kse		*kcb_kse;
62118510Sdeischen	struct kse_mailbox	kcb_kmbx;
63116771Smarcel};
64116771Smarcel
65118510Sdeischenstruct tcb {
66133756Sdfr	struct tcb		*tcb_self;	/* required by rtld */
67133756Sdfr	void			*tcb_dtv;	/* required by rtld */
68118510Sdeischen	struct pthread		*tcb_thread;
69118510Sdeischen	void			*tcb_spare;	/* align tcb_tmbx to 16 bytes */
70118510Sdeischen	struct kse_thr_mailbox	tcb_tmbx;
71118510Sdeischen};
72118277Sdeischen
73118510Sdeischen/*
74118510Sdeischen * Evaluates to the byte offset of the per-kse variable name.
75118510Sdeischen */
76118510Sdeischen#define	__kcb_offset(name)	__offsetof(struct kcb, name)
77118510Sdeischen
78118510Sdeischen/*
79118510Sdeischen * Evaluates to the type of the per-kse variable name.
80118510Sdeischen */
81118510Sdeischen#define	__kcb_type(name)	__typeof(((struct kcb *)0)->name)
82118510Sdeischen
83118510Sdeischen/*
84118510Sdeischen * Evaluates to the value of the per-kse variable name.
85118510Sdeischen */
86118510Sdeischen#define	KCB_GET32(name) ({					\
87118510Sdeischen	__kcb_type(name) __result;				\
88118510Sdeischen								\
89118510Sdeischen	u_int __i;						\
90118510Sdeischen	__asm __volatile("movl %%gs:%1, %0"			\
91118510Sdeischen	    : "=r" (__i)					\
92118510Sdeischen	    : "m" (*(u_int *)(__kcb_offset(name))));		\
93134326Sdavidxu	__result = (__kcb_type(name))__i;			\
94118510Sdeischen								\
95118510Sdeischen	__result;						\
96118510Sdeischen})
97118510Sdeischen
98118510Sdeischen/*
99118510Sdeischen * Sets the value of the per-kse variable name to value val.
100118510Sdeischen */
101118510Sdeischen#define	KCB_SET32(name, val) ({					\
102118510Sdeischen	__kcb_type(name) __val = (val);				\
103118510Sdeischen								\
104118510Sdeischen	u_int __i;						\
105134319Sdavidxu	__i = (u_int)__val;					\
106118510Sdeischen	__asm __volatile("movl %1,%%gs:%0"			\
107118510Sdeischen	    : "=m" (*(u_int *)(__kcb_offset(name)))		\
108118510Sdeischen	    : "r" (__i));					\
109118510Sdeischen})
110118510Sdeischen
111118510Sdeischenstatic __inline u_long
112118510Sdeischen__kcb_readandclear32(volatile u_long *addr)
113118510Sdeischen{
114118510Sdeischen	u_long result;
115118510Sdeischen
116118510Sdeischen	__asm __volatile (
117118510Sdeischen	    "	xorl	%0, %0;"
118118510Sdeischen	    "	xchgl	%%gs:%1, %0;"
119118510Sdeischen	    "# __kcb_readandclear32"
120118510Sdeischen	    : "=&r" (result)
121118510Sdeischen	    : "m" (*addr));
122118510Sdeischen	return (result);
123118510Sdeischen}
124118510Sdeischen
125118510Sdeischen#define	KCB_READANDCLEAR32(name) ({				\
126118510Sdeischen	__kcb_type(name) __result;				\
127118510Sdeischen								\
128118510Sdeischen	__result = (__kcb_type(name))				\
129118510Sdeischen	    __kcb_readandclear32((u_long *)__kcb_offset(name)); \
130118510Sdeischen	__result;						\
131118510Sdeischen})
132118510Sdeischen
133118510Sdeischen
134118510Sdeischen#define	_kcb_curkcb()		KCB_GET32(kcb_self)
135118510Sdeischen#define	_kcb_curtcb()		KCB_GET32(kcb_curtcb)
136118510Sdeischen#define	_kcb_curkse()		((struct kse *)KCB_GET32(kcb_kmbx.km_udata))
137118510Sdeischen#define	_kcb_get_tmbx()		KCB_GET32(kcb_kmbx.km_curthread)
138118510Sdeischen#define	_kcb_set_tmbx(value)	KCB_SET32(kcb_kmbx.km_curthread, (void *)value)
139118510Sdeischen#define	_kcb_readandclear_tmbx() KCB_READANDCLEAR32(kcb_kmbx.km_curthread)
140118510Sdeischen
141118510Sdeischen
142118510Sdeischen/*
143118510Sdeischen * The constructors.
144118510Sdeischen */
145133756Sdfrstruct tcb	*_tcb_ctor(struct pthread *, int);
146118510Sdeischenvoid		_tcb_dtor(struct tcb *tcb);
147118510Sdeischenstruct kcb	*_kcb_ctor(struct kse *);
148118510Sdeischenvoid		_kcb_dtor(struct kcb *);
149118510Sdeischen
150118510Sdeischen/* Called from the KSE to set its private data. */
151118510Sdeischenstatic __inline void
152118510Sdeischen_kcb_set(struct kcb *kcb)
153118510Sdeischen{
154147673Speter	i386_set_gsbase(kcb);
155118510Sdeischen}
156118510Sdeischen
157118510Sdeischen/* Get the current kcb. */
158118510Sdeischenstatic __inline struct kcb *
159118510Sdeischen_kcb_get(void)
160118510Sdeischen{
161118510Sdeischen	return (_kcb_curkcb());
162118510Sdeischen}
163118510Sdeischen
164118510Sdeischenstatic __inline struct kse_thr_mailbox *
165118510Sdeischen_kcb_critical_enter(void)
166118510Sdeischen{
167118510Sdeischen	struct kse_thr_mailbox *crit;
168118510Sdeischen
169118510Sdeischen	crit = _kcb_readandclear_tmbx();
170118510Sdeischen	return (crit);
171118510Sdeischen}
172118510Sdeischen
173118510Sdeischenstatic __inline void
174118510Sdeischen_kcb_critical_leave(struct kse_thr_mailbox *crit)
175118510Sdeischen{
176118510Sdeischen	_kcb_set_tmbx(crit);
177118510Sdeischen}
178118510Sdeischen
179118277Sdeischenstatic __inline int
180118510Sdeischen_kcb_in_critical(void)
181118277Sdeischen{
182118510Sdeischen	return (_kcb_get_tmbx() == NULL);
183118510Sdeischen}
184118510Sdeischen
185118510Sdeischenstatic __inline void
186118510Sdeischen_tcb_set(struct kcb *kcb, struct tcb *tcb)
187118510Sdeischen{
188118510Sdeischen	kcb->kcb_curtcb = tcb;
189118510Sdeischen}
190118510Sdeischen
191118510Sdeischenstatic __inline struct tcb *
192118510Sdeischen_tcb_get(void)
193118510Sdeischen{
194118510Sdeischen	return (_kcb_curtcb());
195118510Sdeischen}
196118510Sdeischen
197118510Sdeischenstatic __inline struct pthread *
198118510Sdeischen_get_curthread(void)
199118510Sdeischen{
200118510Sdeischen	struct tcb *tcb;
201118510Sdeischen
202118510Sdeischen	tcb = _kcb_curtcb();
203118510Sdeischen	if (tcb != NULL)
204118510Sdeischen		return (tcb->tcb_thread);
205118510Sdeischen	else
206118510Sdeischen		return (NULL);
207118510Sdeischen}
208118510Sdeischen
209118510Sdeischenstatic __inline struct kse *
210118510Sdeischen_get_curkse(void)
211118510Sdeischen{
212118510Sdeischen	return ((struct kse *)_kcb_curkse());
213118510Sdeischen}
214118510Sdeischen
215118510Sdeischenvoid	_i386_enter_uts(struct kse_mailbox *km, kse_func_t uts, void *stack,
216118510Sdeischen    size_t stacksz);
217118510Sdeischen
218118510Sdeischenstatic __inline int
219118510Sdeischen_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
220118510Sdeischen{
221118277Sdeischen	int ret;
222118277Sdeischen
223118510Sdeischen	ret = _thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext);
224118277Sdeischen	if (ret == 0) {
225118510Sdeischen		_i386_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func,
226118510Sdeischen		    kcb->kcb_kmbx.km_stack.ss_sp,
227118510Sdeischen		    kcb->kcb_kmbx.km_stack.ss_size);
228118277Sdeischen		/* We should not reach here. */
229118277Sdeischen		return (-1);
230118277Sdeischen	}
231118277Sdeischen	else if (ret < 0)
232118277Sdeischen		return (-1);
233118277Sdeischen	return (0);
234118277Sdeischen}
235118277Sdeischen
236118277Sdeischenstatic __inline int
237118510Sdeischen_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
238118277Sdeischen{
239132125Sdavidxu	extern int _libkse_debug;
240132125Sdavidxu
241118510Sdeischen	if ((kcb == NULL) || (tcb == NULL))
242118510Sdeischen		return (-1);
243118510Sdeischen	kcb->kcb_curtcb = tcb;
244132125Sdavidxu	if (_libkse_debug == 0) {
245132125Sdavidxu		tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
246132125Sdavidxu		if (setmbox != 0)
247132125Sdavidxu			_thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
248132125Sdavidxu			    (intptr_t)&tcb->tcb_tmbx,
249174112Sdeischen			    (intptr_t *)(void *)&kcb->kcb_kmbx.km_curthread);
250132125Sdavidxu		else
251132125Sdavidxu			_thr_setcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext,
252132125Sdavidxu				0, NULL);
253132125Sdavidxu	} else {
254132125Sdavidxu		if (setmbox)
255132125Sdavidxu			kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
256132125Sdavidxu		else
257132125Sdavidxu			kse_switchin(&tcb->tcb_tmbx, 0);
258132125Sdavidxu	}
259132125Sdavidxu
260118277Sdeischen	/* We should not reach here. */
261118277Sdeischen	return (-1);
262118277Sdeischen}
263118277Sdeischen
264113656Sdeischen#endif
265