pthread_md.h revision 161830
1132400Sgrehan/* 2161802Smarcel * Copyright 2004 by Peter Grehan. 3161802Smarcel * Copyright 2006 Marcel Moolenaar 4161802Smarcel * All rights reserved. 5132400Sgrehan * 6132400Sgrehan * Redistribution and use in source and binary forms, with or without 7132400Sgrehan * modification, are permitted provided that the following conditions 8132400Sgrehan * are met: 9132400Sgrehan * 1. Redistributions of source code must retain the above copyright 10132400Sgrehan * notice, this list of conditions and the following disclaimer. 11132400Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 12132400Sgrehan * notice, this list of conditions and the following disclaimer in the 13132400Sgrehan * documentation and/or other materials provided with the distribution. 14132400Sgrehan * 3. The name of the author may not be used to endorse or promote products 15132400Sgrehan * derived from this software without specific prior written permission. 16132400Sgrehan * 17132400Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18132400Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19132400Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20132400Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21132400Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22132400Sgrehan * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23132400Sgrehan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24132400Sgrehan * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25132400Sgrehan * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26132400Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27132400Sgrehan * SUCH DAMAGE. 28132400Sgrehan * 29132400Sgrehan * $FreeBSD: head/lib/libkse/arch/powerpc/include/pthread_md.h 161830 2006-09-01 19:13:36Z marcel $ 30132400Sgrehan */ 31132400Sgrehan 32132400Sgrehan/* 33132400Sgrehan * Machine-dependent thread prototypes/definitions for the thread kernel. 34132400Sgrehan */ 35132400Sgrehan#ifndef _PTHREAD_MD_H_ 36132400Sgrehan#define _PTHREAD_MD_H_ 37132400Sgrehan 38132400Sgrehan#include <sys/kse.h> 39132400Sgrehan#include <stddef.h> 40132400Sgrehan#include <ucontext.h> 41132400Sgrehan 42132400Sgrehanextern void _ppc32_enter_uts(struct kse_mailbox *, kse_func_t, void *, size_t); 43132400Sgrehanextern int _ppc32_setcontext(mcontext_t *, intptr_t, intptr_t *); 44132400Sgrehanextern int _ppc32_getcontext(mcontext_t *); 45132400Sgrehan 46132400Sgrehan#define KSE_STACKSIZE 16384 47161802Smarcel#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_dtv) 48132400Sgrehan 49132400Sgrehan#define THR_GETCONTEXT(ucp) _ppc32_getcontext(&(ucp)->uc_mcontext) 50132400Sgrehan#define THR_SETCONTEXT(ucp) _ppc32_setcontext(&(ucp)->uc_mcontext, 0, NULL) 51132400Sgrehan 52132400Sgrehan#define PER_THREAD 53132400Sgrehan 54132400Sgrehanstruct kcb; 55132400Sgrehanstruct kse; 56132400Sgrehanstruct pthread; 57132400Sgrehanstruct tcb; 58132400Sgrehan 59132400Sgrehan/* 60161828Smarcel * %r2 points to the following. 61132400Sgrehan */ 62132400Sgrehanstruct ppc32_tp { 63161802Smarcel void *tp_dtv; /* dynamic thread vector */ 64132400Sgrehan uint32_t _reserved_; 65161802Smarcel double tp_tls[0]; /* static TLS */ 66132400Sgrehan}; 67132400Sgrehan 68132400Sgrehanstruct tcb { 69132400Sgrehan struct kse_thr_mailbox tcb_tmbx; 70132400Sgrehan struct pthread *tcb_thread; 71132400Sgrehan struct kcb *tcb_curkcb; 72132400Sgrehan long tcb_isfake; 73161830Smarcel long tcb_spare[3]; 74132400Sgrehan struct ppc32_tp tcb_tp; 75132400Sgrehan}; 76132400Sgrehan 77132400Sgrehanstruct kcb { 78132400Sgrehan struct kse_mailbox kcb_kmbx; 79161802Smarcel struct kse *kcb_kse; 80161802Smarcel struct tcb *kcb_curtcb; 81132400Sgrehan struct tcb kcb_faketcb; 82132400Sgrehan}; 83132400Sgrehan 84132400Sgrehan/* 85132400Sgrehan * From the PowerPC32 TLS spec: 86132400Sgrehan * 87132400Sgrehan * "r2 is the thread pointer, and points 0x7000 past the end of the 88132400Sgrehan * thread control block." Or, 0x7008 past the start of the 8-byte tcb 89132400Sgrehan */ 90132400Sgrehan#define TP_OFFSET 0x7008 91132400Sgrehan 92161828Smarcelstatic __inline char * 93161828Smarcelppc_get_tp() 94161828Smarcel{ 95161828Smarcel register char *r2 __asm__("%r2"); 96132400Sgrehan 97161828Smarcel return (r2 - TP_OFFSET); 98161828Smarcel} 99161828Smarcel 100161828Smarcelstatic __inline void 101161828Smarcelppc_set_tp(char *tp) 102161828Smarcel{ 103161828Smarcel register char *r2 __asm__("%r2"); 104161828Smarcel __asm __volatile("mr %0,%1" : "=r"(r2) : "r"(tp + TP_OFFSET)); 105161828Smarcel} 106161828Smarcel 107161828Smarcelstatic __inline struct tcb * 108161828Smarcelppc_get_tcb() 109161828Smarcel{ 110161828Smarcel return ((struct tcb *)(ppc_get_tp() - offsetof(struct tcb, tcb_tp))); 111161828Smarcel} 112161828Smarcel 113161828Smarcelstatic __inline void 114161828Smarcelppc_set_tcb(struct tcb *tcb) 115161828Smarcel{ 116161828Smarcel ppc_set_tp((char*)&tcb->tcb_tp); 117161828Smarcel} 118161828Smarcel 119132400Sgrehan/* 120132400Sgrehan * The kcb and tcb constructors. 121132400Sgrehan */ 122133806Sgrehanstruct tcb *_tcb_ctor(struct pthread *, int); 123132400Sgrehanvoid _tcb_dtor(struct tcb *); 124132400Sgrehanstruct kcb *_kcb_ctor(struct kse *kse); 125132400Sgrehanvoid _kcb_dtor(struct kcb *); 126132400Sgrehan 127132400Sgrehan/* Called from the KSE to set its private data. */ 128132400Sgrehanstatic __inline void 129132400Sgrehan_kcb_set(struct kcb *kcb) 130132400Sgrehan{ 131132400Sgrehan /* There is no thread yet; use the fake tcb. */ 132161828Smarcel ppc_set_tcb(&kcb->kcb_faketcb); 133132400Sgrehan} 134132400Sgrehan 135132400Sgrehan/* 136132400Sgrehan * Get the current kcb. 137132400Sgrehan * 138132400Sgrehan * This can only be called while in a critical region; don't 139132400Sgrehan * worry about having the kcb changed out from under us. 140132400Sgrehan */ 141132400Sgrehanstatic __inline struct kcb * 142132400Sgrehan_kcb_get(void) 143132400Sgrehan{ 144161828Smarcel return (ppc_get_tcb()->tcb_curkcb); 145132400Sgrehan} 146132400Sgrehan 147132400Sgrehan/* 148132400Sgrehan * Enter a critical region. 149132400Sgrehan * 150132400Sgrehan * Read and clear km_curthread in the kse mailbox. 151132400Sgrehan */ 152132400Sgrehanstatic __inline struct kse_thr_mailbox * 153132400Sgrehan_kcb_critical_enter(void) 154132400Sgrehan{ 155132400Sgrehan struct kse_thr_mailbox *crit; 156161828Smarcel struct tcb *tcb; 157132400Sgrehan uint32_t flags; 158132400Sgrehan 159161828Smarcel tcb = ppc_get_tcb(); 160161828Smarcel if (tcb->tcb_isfake != 0) { 161132400Sgrehan /* 162132400Sgrehan * We already are in a critical region since 163132400Sgrehan * there is no current thread. 164132400Sgrehan */ 165132400Sgrehan crit = NULL; 166132400Sgrehan } else { 167161828Smarcel flags = tcb->tcb_tmbx.tm_flags; 168161828Smarcel tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; 169161828Smarcel crit = tcb->tcb_curkcb->kcb_kmbx.km_curthread; 170161828Smarcel tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL; 171161828Smarcel tcb->tcb_tmbx.tm_flags = flags; 172132400Sgrehan } 173132400Sgrehan return (crit); 174132400Sgrehan} 175132400Sgrehan 176132400Sgrehanstatic __inline void 177132400Sgrehan_kcb_critical_leave(struct kse_thr_mailbox *crit) 178132400Sgrehan{ 179161828Smarcel struct tcb *tcb; 180161828Smarcel 181161828Smarcel tcb = ppc_get_tcb(); 182161828Smarcel 183161828Smarcel /* No need to do anything if this is a fake tcb. */ 184161828Smarcel if (tcb->tcb_isfake == 0) 185161828Smarcel tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit; 186132400Sgrehan} 187132400Sgrehan 188132400Sgrehanstatic __inline int 189132400Sgrehan_kcb_in_critical(void) 190132400Sgrehan{ 191161828Smarcel struct tcb *tcb; 192132400Sgrehan uint32_t flags; 193132400Sgrehan int ret; 194132400Sgrehan 195161828Smarcel tcb = ppc_get_tcb(); 196161828Smarcel if (tcb->tcb_isfake != 0) { 197132400Sgrehan /* 198132400Sgrehan * We are in a critical region since there is no 199132400Sgrehan * current thread. 200132400Sgrehan */ 201132400Sgrehan ret = 1; 202132400Sgrehan } else { 203161828Smarcel flags = tcb->tcb_tmbx.tm_flags; 204161828Smarcel tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; 205161828Smarcel ret = (tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL); 206161828Smarcel tcb->tcb_tmbx.tm_flags = flags; 207132400Sgrehan } 208132400Sgrehan return (ret); 209132400Sgrehan} 210132400Sgrehan 211132400Sgrehanstatic __inline void 212132400Sgrehan_tcb_set(struct kcb *kcb, struct tcb *tcb) 213132400Sgrehan{ 214132400Sgrehan if (tcb == NULL) 215132400Sgrehan tcb = &kcb->kcb_faketcb; 216132400Sgrehan kcb->kcb_curtcb = tcb; 217132400Sgrehan tcb->tcb_curkcb = kcb; 218161828Smarcel ppc_set_tcb(tcb); 219132400Sgrehan} 220132400Sgrehan 221132400Sgrehanstatic __inline struct tcb * 222132400Sgrehan_tcb_get(void) 223132400Sgrehan{ 224161828Smarcel return (ppc_get_tcb()); 225132400Sgrehan} 226132400Sgrehan 227132400Sgrehanstatic __inline struct pthread * 228132400Sgrehan_get_curthread(void) 229132400Sgrehan{ 230161828Smarcel return (ppc_get_tcb()->tcb_thread); 231132400Sgrehan} 232132400Sgrehan 233132400Sgrehan/* 234132400Sgrehan * Get the current kse. 235132400Sgrehan * 236132400Sgrehan * Like _kcb_get(), this can only be called while in a critical region. 237132400Sgrehan */ 238132400Sgrehanstatic __inline struct kse * 239132400Sgrehan_get_curkse(void) 240132400Sgrehan{ 241161828Smarcel return (ppc_get_tcb()->tcb_curkcb->kcb_kse); 242132400Sgrehan} 243132400Sgrehan 244132400Sgrehanstatic __inline int 245132400Sgrehan_thread_enter_uts(struct tcb *tcb, struct kcb *kcb) 246132400Sgrehan{ 247132400Sgrehan if (_ppc32_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) { 248132400Sgrehan /* Make the fake tcb the current thread. */ 249132400Sgrehan kcb->kcb_curtcb = &kcb->kcb_faketcb; 250161828Smarcel ppc_set_tcb(&kcb->kcb_faketcb); 251132400Sgrehan _ppc32_enter_uts(&kcb->kcb_kmbx, kcb->kcb_kmbx.km_func, 252132400Sgrehan kcb->kcb_kmbx.km_stack.ss_sp, 253132400Sgrehan kcb->kcb_kmbx.km_stack.ss_size - 32); 254132400Sgrehan /* We should not reach here. */ 255132400Sgrehan return (-1); 256132400Sgrehan } 257132400Sgrehan return (0); 258132400Sgrehan} 259132400Sgrehan 260132400Sgrehanstatic __inline int 261132400Sgrehan_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox) 262132400Sgrehan{ 263132400Sgrehan mcontext_t *mc; 264132400Sgrehan extern int _libkse_debug; 265132400Sgrehan 266132400Sgrehan _tcb_set(kcb, tcb); 267132400Sgrehan mc = &tcb->tcb_tmbx.tm_context.uc_mcontext; 268132400Sgrehan 269132400Sgrehan /* 270132400Sgrehan * A full context needs a system call to restore, so use 271132400Sgrehan * kse_switchin. Otherwise, the partial context can be 272132400Sgrehan * restored with _ppc32_setcontext 273132400Sgrehan */ 274132400Sgrehan if (mc->mc_vers != _MC_VERSION_KSE && _libkse_debug != 0) { 275132400Sgrehan if (setmbox) 276132400Sgrehan kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX); 277161828Smarcel else 278161828Smarcel kse_switchin(&tcb->tcb_tmbx, 0); 279132400Sgrehan } else { 280132400Sgrehan tcb->tcb_tmbx.tm_lwp = kcb->kcb_kmbx.km_lwp; 281132400Sgrehan if (setmbox) 282132400Sgrehan _ppc32_setcontext(mc, (intptr_t)&tcb->tcb_tmbx, 283132400Sgrehan (intptr_t *)&kcb->kcb_kmbx.km_curthread); 284132400Sgrehan else 285132400Sgrehan _ppc32_setcontext(mc, 0, NULL); 286132400Sgrehan } 287132400Sgrehan 288132400Sgrehan /* We should not reach here. */ 289132400Sgrehan return (-1); 290132400Sgrehan} 291132400Sgrehan 292132400Sgrehan#endif /* _PTHREAD_MD_H_ */ 293