1120924Sdeischen/*-
2120924Sdeischen * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>.
3120924Sdeischen * Copyright (c) 2003 Marcel Moolenaar
4120924Sdeischen * All rights reserved.
5120924Sdeischen *
6120924Sdeischen * Redistribution and use in source and binary forms, with or without
7120924Sdeischen * modification, are permitted provided that the following conditions
8120924Sdeischen * are met:
9120924Sdeischen *
10120924Sdeischen * 1. Redistributions of source code must retain the above copyright
11120924Sdeischen *    notice, this list of conditions and the following disclaimer.
12120924Sdeischen * 2. Redistributions in binary form must reproduce the above copyright
13120924Sdeischen *    notice, this list of conditions and the following disclaimer in the
14120924Sdeischen *    documentation and/or other materials provided with the distribution.
15120924Sdeischen *
16120924Sdeischen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17120924Sdeischen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18120924Sdeischen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19120924Sdeischen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20120924Sdeischen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21120924Sdeischen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22120924Sdeischen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23120924Sdeischen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24120924Sdeischen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25120924Sdeischen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26120924Sdeischen *
27120924Sdeischen * $FreeBSD$
28120924Sdeischen */
29120924Sdeischen
30120924Sdeischen/*
31120924Sdeischen * Machine-dependent thread prototypes/definitions for the thread kernel.
32120924Sdeischen */
33120924Sdeischen#ifndef _PTHREAD_MD_H_
34120924Sdeischen#define	_PTHREAD_MD_H_
35120924Sdeischen
36120924Sdeischen#include <sys/kse.h>
37120924Sdeischen#include <stddef.h>
38120924Sdeischen#include <ucontext.h>
39120924Sdeischen
40120924Sdeischen#define	KSE_STACKSIZE		16384
41133857Sdavidxu#define	DTV_OFFSET		offsetof(struct tcb, tcb_tp.tp_tdv)
42120924Sdeischen
43120924Sdeischenint _thr_setcontext(mcontext_t *, intptr_t, intptr_t *);
44120924Sdeischenint _thr_getcontext(mcontext_t *);
45120924Sdeischen
46120924Sdeischen#define	THR_GETCONTEXT(ucp)	_thr_getcontext(&(ucp)->uc_mcontext)
47120924Sdeischen#define	THR_SETCONTEXT(ucp)	_thr_setcontext(&(ucp)->uc_mcontext, 0, NULL)
48120924Sdeischen
49120924Sdeischen#define	PER_THREAD
50120924Sdeischen
51120924Sdeischenstruct kcb;
52120924Sdeischenstruct kse;
53120924Sdeischenstruct pthread;
54120924Sdeischenstruct tcb;
55120924Sdeischenstruct tdv;	/* We don't know what this is yet? */
56120924Sdeischen
57120924Sdeischen
58120924Sdeischen/*
59120924Sdeischen * %g6 points to one of these. We define the static TLS as an array
60120924Sdeischen * of long double to enforce 16-byte alignment of the TLS memory.
61120924Sdeischen *
62120924Sdeischen * XXX - Both static and dynamic allocation of any of these structures
63120924Sdeischen *       will result in a valid, well-aligned thread pointer???
64120924Sdeischen */
65120924Sdeischenstruct sparc64_tp {
66120924Sdeischen	struct tdv		*tp_tdv;	/* dynamic TLS */
67120924Sdeischen	uint64_t		_reserved_;
68120924Sdeischen	long double		tp_tls[0];	/* static TLS */
69120924Sdeischen};
70120924Sdeischen
71120924Sdeischenstruct tcb {
72120924Sdeischen	struct pthread		*tcb_thread;
73120924Sdeischen	void			*tcb_addr;	/* allocated tcb address */
74120924Sdeischen	struct kcb		*tcb_curkcb;
75120924Sdeischen	uint64_t		tcb_isfake;
76120924Sdeischen	uint64_t		tcb_spare[4];
77120924Sdeischen	struct kse_thr_mailbox	tcb_tmbx;	/* needs 64-byte alignment */
78120924Sdeischen	struct sparc64_tp	tcb_tp;
79120924Sdeischen} __aligned(64);
80120924Sdeischen
81120924Sdeischenstruct kcb {
82120924Sdeischen	struct kse_mailbox	kcb_kmbx;
83120924Sdeischen	struct tcb		kcb_faketcb;
84120924Sdeischen	struct tcb		*kcb_curtcb;
85120924Sdeischen	struct kse		*kcb_kse;
86120924Sdeischen};
87120924Sdeischen
88120924Sdeischenregister struct sparc64_tp *_tp __asm("%g6");
89120924Sdeischen
90120924Sdeischen#define	_tcb	((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
91120924Sdeischen
92120924Sdeischen/*
93120924Sdeischen * The kcb and tcb constructors.
94120924Sdeischen */
95133756Sdfrstruct tcb	*_tcb_ctor(struct pthread *, int);
96120924Sdeischenvoid		_tcb_dtor(struct tcb *);
97120924Sdeischenstruct kcb	*_kcb_ctor(struct kse *kse);
98120924Sdeischenvoid		_kcb_dtor(struct kcb *);
99120924Sdeischen
100120924Sdeischen/* Called from the KSE to set its private data. */
101120924Sdeischenstatic __inline void
102120924Sdeischen_kcb_set(struct kcb *kcb)
103120924Sdeischen{
104120924Sdeischen	/* There is no thread yet; use the fake tcb. */
105120924Sdeischen	_tp = &kcb->kcb_faketcb.tcb_tp;
106120924Sdeischen}
107120924Sdeischen
108120924Sdeischen/*
109120924Sdeischen * Get the current kcb.
110120924Sdeischen *
111120924Sdeischen * This can only be called while in a critical region; don't
112120924Sdeischen * worry about having the kcb changed out from under us.
113120924Sdeischen */
114120924Sdeischenstatic __inline struct kcb *
115120924Sdeischen_kcb_get(void)
116120924Sdeischen{
117120924Sdeischen	return (_tcb->tcb_curkcb);
118120924Sdeischen}
119120924Sdeischen
120120924Sdeischen/*
121120924Sdeischen * Enter a critical region.
122120924Sdeischen *
123120924Sdeischen * Read and clear km_curthread in the kse mailbox.
124120924Sdeischen */
125120924Sdeischenstatic __inline struct kse_thr_mailbox *
126120924Sdeischen_kcb_critical_enter(void)
127120924Sdeischen{
128120924Sdeischen	struct kse_thr_mailbox *crit;
129120924Sdeischen	uint32_t flags;
130120924Sdeischen
131120924Sdeischen	if (_tcb->tcb_isfake != 0) {
132120924Sdeischen		/*
133120924Sdeischen		 * We already are in a critical region since
134120924Sdeischen		 * there is no current thread.
135120924Sdeischen		 */
136120924Sdeischen		crit = NULL;
137120924Sdeischen	} else {
138120924Sdeischen		flags = _tcb->tcb_tmbx.tm_flags;
139120924Sdeischen		_tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
140120924Sdeischen		crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread;
141120924Sdeischen		_tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL;
142120924Sdeischen		_tcb->tcb_tmbx.tm_flags = flags;
143120924Sdeischen	}
144120924Sdeischen	return (crit);
145120924Sdeischen}
146120924Sdeischen
147120924Sdeischenstatic __inline void
148120924Sdeischen_kcb_critical_leave(struct kse_thr_mailbox *crit)
149120924Sdeischen{
150120924Sdeischen	/* No need to do anything if this is a fake tcb. */
151120924Sdeischen	if (_tcb->tcb_isfake == 0)
152120924Sdeischen		_tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit;
153120924Sdeischen}
154120924Sdeischen
155120924Sdeischenstatic __inline int
156120924Sdeischen_kcb_in_critical(void)
157120924Sdeischen{
158120924Sdeischen	uint32_t flags;
159120924Sdeischen	int ret;
160120924Sdeischen
161120924Sdeischen	if (_tcb->tcb_isfake != 0) {
162120924Sdeischen		/*
163120924Sdeischen		 * We are in a critical region since there is no
164120924Sdeischen		 * current thread.
165120924Sdeischen		 */
166120924Sdeischen		ret = 1;
167120924Sdeischen	} else {
168120924Sdeischen		flags = _tcb->tcb_tmbx.tm_flags;
169120924Sdeischen		_tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL;
170120924Sdeischen		ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL);
171120924Sdeischen		_tcb->tcb_tmbx.tm_flags = flags;
172120924Sdeischen	}
173120924Sdeischen	return (ret);
174120924Sdeischen}
175120924Sdeischen
176120924Sdeischenstatic __inline void
177120924Sdeischen_tcb_set(struct kcb *kcb, struct tcb *tcb)
178120924Sdeischen{
179120924Sdeischen	if (tcb == NULL)
180120924Sdeischen		tcb = &kcb->kcb_faketcb;
181120924Sdeischen	kcb->kcb_curtcb = tcb;
182120924Sdeischen	tcb->tcb_curkcb = kcb;
183120924Sdeischen	_tp = &tcb->tcb_tp;
184120924Sdeischen}
185120924Sdeischen
186120924Sdeischenstatic __inline struct tcb *
187120924Sdeischen_tcb_get(void)
188120924Sdeischen{
189120924Sdeischen	return (_tcb);
190120924Sdeischen}
191120924Sdeischen
192120924Sdeischenstatic __inline struct pthread *
193120924Sdeischen_get_curthread(void)
194120924Sdeischen{
195120924Sdeischen	return (_tcb->tcb_thread);
196120924Sdeischen}
197120924Sdeischen
198120924Sdeischen/*
199120924Sdeischen * Get the current kse.
200120924Sdeischen *
201120924Sdeischen * Like _kcb_get(), this can only be called while in a critical region.
202120924Sdeischen */
203120924Sdeischenstatic __inline struct kse *
204120924Sdeischen_get_curkse(void)
205120924Sdeischen{
206120924Sdeischen	return (_tcb->tcb_curkcb->kcb_kse);
207120924Sdeischen}
208120924Sdeischen
209120924Sdeischenvoid _sparc64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack,
210120924Sdeischen    size_t stacksz);
211120924Sdeischen
212120924Sdeischenstatic __inline int
213120924Sdeischen_thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
214120924Sdeischen{
215120924Sdeischen	if (_thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
216120924Sdeischen		/* Make the fake tcb the current thread. */
217120924Sdeischen		kcb->kcb_curtcb = &kcb->kcb_faketcb;
218120924Sdeischen		_tp = &kcb->kcb_faketcb.tcb_tp;
219120924Sdeischen		_sparc64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx,
220120924Sdeischen		    kcb->kcb_kmbx.km_stack.ss_sp,
221120924Sdeischen		    kcb->kcb_kmbx.km_stack.ss_size);
222120924Sdeischen		/* We should not reach here. */
223120924Sdeischen		return (-1);
224120924Sdeischen	}
225120924Sdeischen	return (0);
226120924Sdeischen}
227120924Sdeischen
228120924Sdeischenstatic __inline int
229120924Sdeischen_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox)
230120924Sdeischen{
231132125Sdavidxu	extern int _libkse_debug;
232120924Sdeischen	mcontext_t *mc;
233120924Sdeischen
234120924Sdeischen	_tcb_set(kcb, tcb);
235120924Sdeischen	mc = &tcb->tcb_tmbx.tm_context.uc_mcontext;
236132125Sdavidxu	if (_libkse_debug == 0) {
237132125Sdavidxu		tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp;
238132125Sdavidxu		if (setmbox)
239132125Sdavidxu			_thr_setcontext(mc, (intptr_t)&tcb->tcb_tmbx,
240174112Sdeischen			    (intptr_t *)(void *)&kcb->kcb_kmbx.km_curthread);
241132125Sdavidxu		else
242132125Sdavidxu			_thr_setcontext(mc, 0, NULL);
243132125Sdavidxu	} else {
244132125Sdavidxu		if (setmbox)
245132125Sdavidxu			kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX);
246132125Sdavidxu		else
247132125Sdavidxu			kse_switchin(&tcb->tcb_tmbx, 0);
248132125Sdavidxu	}
249132125Sdavidxu
250120924Sdeischen	/* We should not reach here. */
251120924Sdeischen	return (-1);
252120924Sdeischen}
253120924Sdeischen
254120924Sdeischen#endif /* _PTHREAD_MD_H_ */
255