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