1116708Smarcel/* 2161802Smarcel * Copyright (c) 2003-2006 Marcel Moolenaar 3116708Smarcel * All rights reserved. 4116708Smarcel * 5116708Smarcel * Redistribution and use in source and binary forms, with or without 6116708Smarcel * modification, are permitted provided that the following conditions 7116708Smarcel * are met: 8116708Smarcel * 9116708Smarcel * 1. Redistributions of source code must retain the above copyright 10116708Smarcel * notice, this list of conditions and the following disclaimer. 11116708Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12116708Smarcel * notice, this list of conditions and the following disclaimer in the 13116708Smarcel * documentation and/or other materials provided with the distribution. 14116708Smarcel * 15116708Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16116708Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17116708Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18116708Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19116708Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20116708Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21116708Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22116708Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23116708Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24116708Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25116708Smarcel * 26116708Smarcel * $FreeBSD$ 27116708Smarcel */ 28116708Smarcel 29116708Smarcel#ifndef _PTHREAD_MD_H_ 30116708Smarcel#define _PTHREAD_MD_H_ 31116708Smarcel 32118510Sdeischen#include <sys/kse.h> 33118518Smarcel#include <stddef.h> 34118510Sdeischen#include <ucontext.h> 35118510Sdeischen 36120263Smarcel#define KSE_STACKSIZE 16384 37161802Smarcel#define DTV_OFFSET offsetof(struct tcb, tcb_tp.tp_dtv) 38120263Smarcel 39118507Smarcel#define THR_GETCONTEXT(ucp) _ia64_save_context(&(ucp)->uc_mcontext) 40120254Smarcel#define THR_SETCONTEXT(ucp) PANIC("THR_SETCONTEXT() now in use!\n") 41116708Smarcel 42118510Sdeischen#define PER_THREAD 43116708Smarcel 44118510Sdeischenstruct kcb; 45118510Sdeischenstruct kse; 46118510Sdeischenstruct pthread; 47118510Sdeischenstruct tcb; 48118510Sdeischen 49118510Sdeischen/* 50161841Smarcel * tp points to one of these. We define the TLS structure as a union 51161841Smarcel * containing a long double to enforce 16-byte alignment. This makes 52161841Smarcel * sure that there will not be any padding in struct tcb after the 53161841Smarcel * TLS structure. 54118510Sdeischen */ 55161841Smarcelunion ia64_tp { 56161841Smarcel void *tp_dtv; 57161841Smarcel long double _align_; 58116771Smarcel}; 59116771Smarcel 60118510Sdeischenstruct tcb { 61118510Sdeischen struct kse_thr_mailbox tcb_tmbx; 62118510Sdeischen struct pthread *tcb_thread; 63118510Sdeischen struct kcb *tcb_curkcb; 64118510Sdeischen long tcb_isfake; 65161841Smarcel union ia64_tp tcb_tp; 66118510Sdeischen}; 67118510Sdeischen 68118510Sdeischenstruct kcb { 69118510Sdeischen struct kse_mailbox kcb_kmbx; 70161802Smarcel struct kse *kcb_kse; 71161802Smarcel struct tcb *kcb_curtcb; 72118510Sdeischen struct tcb kcb_faketcb; 73118510Sdeischen}; 74118510Sdeischen 75161841Smarcelstatic __inline struct tcb * 76174127Srwatsonia64_get_tcb(void) 77161841Smarcel{ 78161841Smarcel register char *tp __asm("%r13"); 79118510Sdeischen 80161841Smarcel return ((struct tcb *)(tp - offsetof(struct tcb, tcb_tp))); 81161841Smarcel} 82118518Smarcel 83161841Smarcelstatic __inline void 84161841Smarcelia64_set_tcb(struct tcb *tcb) 85161841Smarcel{ 86161841Smarcel register char *tp __asm("%r13"); 87161841Smarcel 88161841Smarcel __asm __volatile("mov %0 = %1;;" : "=r"(tp) : "r"(&tcb->tcb_tp)); 89161841Smarcel} 90161841Smarcel 91118510Sdeischen/* 92118510Sdeischen * The kcb and tcb constructors. 93118510Sdeischen */ 94133756Sdfrstruct tcb *_tcb_ctor(struct pthread *, int); 95118510Sdeischenvoid _tcb_dtor(struct tcb *); 96118510Sdeischenstruct kcb *_kcb_ctor(struct kse *kse); 97118510Sdeischenvoid _kcb_dtor(struct kcb *); 98118510Sdeischen 99118510Sdeischen/* Called from the KSE to set its private data. */ 100118510Sdeischenstatic __inline void 101118510Sdeischen_kcb_set(struct kcb *kcb) 102118510Sdeischen{ 103118510Sdeischen /* There is no thread yet; use the fake tcb. */ 104161841Smarcel ia64_set_tcb(&kcb->kcb_faketcb); 105118510Sdeischen} 106118510Sdeischen 107118510Sdeischen/* 108118510Sdeischen * Get the current kcb. 109118510Sdeischen * 110118510Sdeischen * This can only be called while in a critical region; don't 111118510Sdeischen * worry about having the kcb changed out from under us. 112118510Sdeischen */ 113118510Sdeischenstatic __inline struct kcb * 114118510Sdeischen_kcb_get(void) 115118510Sdeischen{ 116161841Smarcel return (ia64_get_tcb()->tcb_curkcb); 117118510Sdeischen} 118118510Sdeischen 119118510Sdeischen/* 120118510Sdeischen * Enter a critical region. 121118510Sdeischen * 122118510Sdeischen * Read and clear km_curthread in the kse mailbox. 123118510Sdeischen */ 124118510Sdeischenstatic __inline struct kse_thr_mailbox * 125118510Sdeischen_kcb_critical_enter(void) 126118510Sdeischen{ 127161841Smarcel struct tcb *tcb; 128118510Sdeischen struct kse_thr_mailbox *crit; 129118510Sdeischen uint32_t flags; 130118510Sdeischen 131161841Smarcel tcb = ia64_get_tcb(); 132161841Smarcel if (tcb->tcb_isfake != 0) { 133118510Sdeischen /* 134118510Sdeischen * We already are in a critical region since 135118510Sdeischen * there is no current thread. 136118510Sdeischen */ 137118510Sdeischen crit = NULL; 138118510Sdeischen } else { 139161841Smarcel flags = tcb->tcb_tmbx.tm_flags; 140161841Smarcel tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; 141161841Smarcel crit = tcb->tcb_curkcb->kcb_kmbx.km_curthread; 142161841Smarcel tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL; 143161841Smarcel tcb->tcb_tmbx.tm_flags = flags; 144118510Sdeischen } 145118510Sdeischen return (crit); 146118510Sdeischen} 147118510Sdeischen 148118510Sdeischenstatic __inline void 149118510Sdeischen_kcb_critical_leave(struct kse_thr_mailbox *crit) 150118510Sdeischen{ 151161841Smarcel struct tcb *tcb; 152161841Smarcel 153161841Smarcel tcb = ia64_get_tcb(); 154118510Sdeischen /* No need to do anything if this is a fake tcb. */ 155161841Smarcel if (tcb->tcb_isfake == 0) 156161841Smarcel tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit; 157118510Sdeischen} 158118510Sdeischen 159118510Sdeischenstatic __inline int 160118510Sdeischen_kcb_in_critical(void) 161118510Sdeischen{ 162161841Smarcel struct tcb *tcb; 163118510Sdeischen uint32_t flags; 164118510Sdeischen int ret; 165118510Sdeischen 166161841Smarcel tcb = ia64_get_tcb(); 167161841Smarcel if (tcb->tcb_isfake != 0) { 168118510Sdeischen /* 169118510Sdeischen * We are in a critical region since there is no 170118510Sdeischen * current thread. 171118510Sdeischen */ 172118510Sdeischen ret = 1; 173118510Sdeischen } else { 174161841Smarcel flags = tcb->tcb_tmbx.tm_flags; 175161841Smarcel tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; 176161841Smarcel ret = (tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL); 177161841Smarcel tcb->tcb_tmbx.tm_flags = flags; 178118510Sdeischen } 179118510Sdeischen return (ret); 180118510Sdeischen} 181118510Sdeischen 182118510Sdeischenstatic __inline void 183118510Sdeischen_tcb_set(struct kcb *kcb, struct tcb *tcb) 184118510Sdeischen{ 185118518Smarcel if (tcb == NULL) 186118518Smarcel tcb = &kcb->kcb_faketcb; 187118518Smarcel kcb->kcb_curtcb = tcb; 188118518Smarcel tcb->tcb_curkcb = kcb; 189161841Smarcel ia64_set_tcb(tcb); 190118510Sdeischen} 191118510Sdeischen 192118510Sdeischenstatic __inline struct tcb * 193118510Sdeischen_tcb_get(void) 194118510Sdeischen{ 195161841Smarcel return (ia64_get_tcb()); 196118510Sdeischen} 197118510Sdeischen 198118510Sdeischenstatic __inline struct pthread * 199118510Sdeischen_get_curthread(void) 200118510Sdeischen{ 201161841Smarcel return (ia64_get_tcb()->tcb_thread); 202118510Sdeischen} 203118510Sdeischen 204118510Sdeischen/* 205118510Sdeischen * Get the current kse. 206118510Sdeischen * 207118519Sdeischen * Like _kcb_get(), this can only be called while in a critical region. 208118510Sdeischen */ 209118510Sdeischenstatic __inline struct kse * 210118510Sdeischen_get_curkse(void) 211118510Sdeischen{ 212161841Smarcel return (ia64_get_tcb()->tcb_curkcb->kcb_kse); 213118510Sdeischen} 214118510Sdeischen 215120254Smarcelvoid _ia64_break_setcontext(mcontext_t *mc); 216116866Smarcelvoid _ia64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack, 217116866Smarcel size_t stacksz); 218116866Smarcelint _ia64_restore_context(mcontext_t *mc, intptr_t val, intptr_t *loc); 219116866Smarcelint _ia64_save_context(mcontext_t *mc); 220116866Smarcel 221116866Smarcelstatic __inline int 222118510Sdeischen_thread_enter_uts(struct tcb *tcb, struct kcb *kcb) 223116866Smarcel{ 224118510Sdeischen if (_ia64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) { 225118510Sdeischen /* Make the fake tcb the current thread. */ 226118510Sdeischen kcb->kcb_curtcb = &kcb->kcb_faketcb; 227161841Smarcel ia64_set_tcb(&kcb->kcb_faketcb); 228118510Sdeischen _ia64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx, 229118510Sdeischen kcb->kcb_kmbx.km_stack.ss_sp, 230118510Sdeischen kcb->kcb_kmbx.km_stack.ss_size); 231116866Smarcel /* We should not reach here. */ 232116866Smarcel return (-1); 233116866Smarcel } 234116866Smarcel return (0); 235116866Smarcel} 236116866Smarcel 237116866Smarcelstatic __inline int 238118510Sdeischen_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox) 239116866Smarcel{ 240118592Smarcel mcontext_t *mc; 241118592Smarcel 242118518Smarcel _tcb_set(kcb, tcb); 243118592Smarcel mc = &tcb->tcb_tmbx.tm_context.uc_mcontext; 244118592Smarcel if (mc->mc_flags & _MC_FLAGS_ASYNC_CONTEXT) { 245118592Smarcel if (setmbox) { 246118592Smarcel mc->mc_flags |= _MC_FLAGS_KSE_SET_MBOX; 247118592Smarcel mc->mc_special.ifa = 248118592Smarcel (intptr_t)&kcb->kcb_kmbx.km_curthread; 249118592Smarcel mc->mc_special.isr = (intptr_t)&tcb->tcb_tmbx; 250118592Smarcel } 251120254Smarcel _ia64_break_setcontext(mc); 252123255Smarcel } else if (mc->mc_flags & _MC_FLAGS_SYSCALL_CONTEXT) { 253123255Smarcel if (setmbox) 254132021Sdavidxu kse_switchin(&tcb->tcb_tmbx, KSE_SWITCHIN_SETTMBX); 255123255Smarcel else 256132021Sdavidxu kse_switchin(&tcb->tcb_tmbx, 0); 257118592Smarcel } else { 258118592Smarcel if (setmbox) 259118592Smarcel _ia64_restore_context(mc, (intptr_t)&tcb->tcb_tmbx, 260118592Smarcel (intptr_t *)&kcb->kcb_kmbx.km_curthread); 261118592Smarcel else 262118592Smarcel _ia64_restore_context(mc, 0, NULL); 263118592Smarcel } 264116866Smarcel /* We should not reach here. */ 265116866Smarcel return (-1); 266116866Smarcel} 267116866Smarcel 268116708Smarcel#endif /* _PTHREAD_MD_H_ */ 269