Index: sys/mips/include/tls.h =================================================================== --- sys/mips/include/tls.h +++ sys/mips/include/tls.h @@ -44,12 +44,14 @@ #define TLS_DTP_OFFSET 0x8000 #ifdef __mips_n64 -#define TLS_TCB_SIZE 16 +#define TLS_TCB_SIZE 16 #ifdef COMPAT_FREEBSD32 -#define TLS_TCB_SIZE32 8 +#define TLS_TCB_SIZE32 8 #endif #else -#define TLS_TCB_SIZE 8 +#define TLS_TCB_SIZE 8 #endif +#define MIPS_TCB_DYNAMIC 0 + #endif /* __MIPS_TLS_H__ */ Index: sys/mips/mips/sys_machdep.c =================================================================== --- sys/mips/mips/sys_machdep.c +++ sys/mips/mips/sys_machdep.c @@ -57,13 +57,41 @@ int sysarch(struct thread *td, struct sysarch_args *uap) { - int error; - void *tlsbase; + int error; + void *tlsbase; +#ifdef MIPS_TCB_DYNAMIC + int tcbsize; + uintptr_t **tp; + uintptr_t *dtv, tls; +#endif switch (uap->op) { case MIPS_SET_TLS: td->td_md.md_tls = uap->parms; +#ifdef MIPS_TCB_DYNAMIC + /* + * Default TCB size is constant TLS_TCB_SIZE, but + * due to alignment TCB may be larger. To identify + * actual size, check first index of dtv array. + */ + tp = td->td_md.md_tls; + dtv = *tp; + +#define MIPS_MAX_TCB_SIZE 0x20 + tls = dtv[2]; + if ((tls > (uintptr_t)tp + TLS_TCB_SIZE) && + ((uintptr_t)tp + MIPS_MAX_TCB_SIZE > tls)) + { + /* At index 0 we found shift of TCB, so let's adjust it */ + tcbsize = tls - (uintptr_t)tp; + } else { + tcbsize = TLS_TCB_SIZE; + } +#undef MIPS_MAX_TCB_SIZE + td->td_md.md_tls_tcb_offset = tcbsize + TLS_TP_OFFSET; +#endif /* MIPS_TCB_DYNAMIC */ + /* * If there is an user local register implementation (ULRI) * update it as well. Add the TLS and TCB offsets so the