Upgrade to glibc-2.19
[akaros.git] / tools / compilers / gcc-glibc / glibc-2.19-akaros / sysdeps / akaros / x86_64 / tls.h
1 /* Definition for thread-local data handling.  nptl/x86_64 version.
2    Copyright (C) 2002-2014 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #ifndef _TLS_H
20 #define _TLS_H  1
21
22 #ifndef __ASSEMBLER__
23 # include <stdbool.h>
24 # include <stddef.h>
25 # include <stdint.h>
26 # include <stdlib.h>
27 # include <sysdep.h>
28 # include <libc-internal.h>
29 # include <kernel-features.h>
30 #include <sys/mman.h>
31 #include <sys/syscall.h>
32 #include <ros/procinfo.h>
33 #include <ros/procdata.h>
34 #include <ros/arch/mmu.h>
35
36 /* Replacement type for __m128 since this file is included by ld.so,
37    which is compiled with -mno-sse.  It must not change the alignment
38    of rtld_savespace_sse.  */
39 typedef struct
40 {
41   int i[4];
42 } __tlsh128bits;
43
44
45 /* Type for the dtv.  */
46 typedef union dtv
47 {
48   size_t counter;
49   struct
50   {
51     void *val;
52     bool is_static;
53   } pointer;
54 } dtv_t;
55
56
57 typedef struct
58 {
59   void *tcb;            /* Pointer to the TCB.  Not necessarily the
60                            thread descriptor used by libpthread.  */
61   dtv_t *dtv;
62   void *self;           /* Pointer to the thread descriptor.  */
63   int multiple_threads;
64   int gscope_flag;
65   uintptr_t sysinfo;
66   uintptr_t stack_guard;
67   uintptr_t pointer_guard;
68   unsigned long int vgetcpu_cache[2];
69 # ifndef __ASSUME_PRIVATE_FUTEX
70   int private_futex;
71 # else
72   int __glibc_reserved1;
73 # endif
74   int rtld_must_xmm_save;
75   /* Reservation of some values for the TM ABI.  */
76   void *__private_tm[4];
77   /* GCC split stack support.  */
78   void *__private_ss;
79   long int __glibc_reserved2;
80   /* Have space for the post-AVX register size.  */
81   __tlsh128bits rtld_savespace_sse[8][4] __attribute__ ((aligned (32)));
82
83   void *__padding[8];
84 } tcbhead_t;
85
86 # define TLS_MULTIPLE_THREADS_IN_TCB 1
87
88 typedef struct rthread {
89     tcbhead_t header;
90 } rthread_t;
91
92 #else /* __ASSEMBLER__ */
93 # include <tcb-offsets.h>
94 #endif
95
96
97 /* Alignment requirement for the stack.  */
98 #define STACK_ALIGN     16
99
100
101 #ifndef __ASSEMBLER__
102 /* Get system call information.  */
103 # include <sysdep.h>
104
105
106 /* Get the thread descriptor definition.  */
107 //# include <nptl/descr.h>
108
109 #ifndef LOCK_PREFIX
110 # ifdef UP
111 #  define LOCK_PREFIX   /* nothing */
112 # else
113 #  define LOCK_PREFIX   "lock;"
114 # endif
115 #endif
116
117 /* This is the size of the initial TCB.  Can't be just sizeof (tcbhead_t),
118    because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole
119    struct rthread even when not linked with -lpthread.  */
120 # define TLS_INIT_TCB_SIZE sizeof (struct rthread)
121
122 /* Alignment requirements for the initial TCB.  */
123 # define TLS_INIT_TCB_ALIGN __alignof__ (struct rthread)
124
125 /* This is the size of the TCB.  */
126 # define TLS_TCB_SIZE sizeof (struct rthread)
127
128 /* Alignment requirements for the TCB.  */
129 # define TLS_TCB_ALIGN __alignof__ (struct rthread)
130
131 /* The TCB can have any size and the memory following the address the
132    thread pointer points to is unspecified.  Allocate the TCB there.  */
133 # define TLS_TCB_AT_TP  1
134
135
136 /* Install the dtv pointer.  The pointer passed is to the element with
137    index -1 which contain the length.  */
138 # define INSTALL_DTV(descr, dtvp) \
139   ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
140
141 /* Install new dtv for current thread.  */
142 # define INSTALL_NEW_DTV(dtvp) \
143   ({ struct rthread *__pd;                                                    \
144      THREAD_SETMEM (__pd, header.dtv, (dtvp)); })
145
146 /* Return dtv of given thread descriptor.  */
147 # define GET_DTV(descr) \
148   (((tcbhead_t *) (descr))->dtv)
149
150
151 /* Code to initially initialize the thread pointer.  This might need
152    special attention since 'errno' is not yet available and if the
153    operation can cause a failure 'errno' must not be touched.  */
154 # define TLS_INIT_TP(thrdescr, secondcall) tls_init_tp(thrdescr)
155
156 /* Return the address of the dtv for the current thread.  */
157 # define THREAD_DTV() \
158   ({ struct rthread *__pd;                                                    \
159      THREAD_GETMEM (__pd, header.dtv); })
160
161 /* Return the thread descriptor for the current thread.
162
163    The contained asm must *not* be marked volatile since otherwise
164    assignments like
165         pthread_descr self = thread_self();
166    do not get optimized away.  */
167 # define THREAD_SELF \
168   ({ struct rthread *__self;                                                  \
169      asm ("movq %%fs:%c1,%q0" : "=r" (__self)                                 \
170           : "i" (offsetof (struct rthread, header.self)));                    \
171      __self;})
172
173 /* Magic for libthread_db to know how to do THREAD_SELF.  */
174 # define DB_THREAD_SELF_INCLUDE  <sys/reg.h> /* For the FS constant.  */
175 # define DB_THREAD_SELF CONST_THREAD_AREA (64, FS)
176
177
178 /* Read member of the thread descriptor directly.  */
179 # define THREAD_GETMEM(descr, member) \
180   ({ __typeof (descr->member) __value;                                        \
181      if (sizeof (__value) == 1)                                               \
182        asm volatile ("movb %%fs:%P2,%b0"                                      \
183                      : "=q" (__value)                                         \
184                      : "0" (0), "i" (offsetof (struct rthread, member)));     \
185      else if (sizeof (__value) == 4)                                          \
186        asm volatile ("movl %%fs:%P1,%0"                                       \
187                      : "=r" (__value)                                         \
188                      : "i" (offsetof (struct rthread, member)));              \
189      else                                                                     \
190        {                                                                      \
191          if (sizeof (__value) != 8)                                           \
192            /* There should not be any value with a size other than 1,         \
193               4 or 8.  */                                                     \
194            abort ();                                                          \
195                                                                               \
196          asm volatile ("movq %%fs:%P1,%q0"                                    \
197                        : "=r" (__value)                                       \
198                        : "i" (offsetof (struct rthread, member)));            \
199        }                                                                      \
200      __value; })
201
202
203 /* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
204 # define THREAD_GETMEM_NC(descr, member, idx) \
205   ({ __typeof (descr->member[0]) __value;                                     \
206      if (sizeof (__value) == 1)                                               \
207        asm volatile ("movb %%fs:%P2(%q3),%b0"                                 \
208                      : "=q" (__value)                                         \
209                      : "0" (0), "i" (offsetof (struct rthread, member[0])),   \
210                        "r" (idx));                                            \
211      else if (sizeof (__value) == 4)                                          \
212        asm volatile ("movl %%fs:%P1(,%q2,4),%0"                               \
213                      : "=r" (__value)                                         \
214                      : "i" (offsetof (struct rthread, member[0])), "r" (idx));\
215      else                                                                     \
216        {                                                                      \
217          if (sizeof (__value) != 8)                                           \
218            /* There should not be any value with a size other than 1,         \
219               4 or 8.  */                                                     \
220            abort ();                                                          \
221                                                                               \
222          asm volatile ("movq %%fs:%P1(,%q2,8),%q0"                            \
223                        : "=r" (__value)                                       \
224                        : "i" (offsetof (struct rthread, member[0])),          \
225                          "r" (idx));                                          \
226        }                                                                      \
227      __value; })
228
229
230 /* Loading addresses of objects on x86-64 needs to be treated special
231    when generating PIC code.  */
232 #ifdef __pic__
233 # define IMM_MODE "nr"
234 #else
235 # define IMM_MODE "ir"
236 #endif
237
238
239 /* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
240 # define THREAD_SETMEM(descr, member, value) \
241   ({ if (sizeof (descr->member) == 1)                                         \
242        asm volatile ("movb %b0,%%fs:%P1" :                                    \
243                      : "iq" (value),                                          \
244                        "i" (offsetof (struct rthread, member)));              \
245      else if (sizeof (descr->member) == 4)                                    \
246        asm volatile ("movl %0,%%fs:%P1" :                                     \
247                      : IMM_MODE (value),                                      \
248                        "i" (offsetof (struct rthread, member)));              \
249      else                                                                     \
250        {                                                                      \
251          if (sizeof (descr->member) != 8)                                     \
252            /* There should not be any value with a size other than 1,         \
253               4 or 8.  */                                                     \
254            abort ();                                                          \
255                                                                               \
256          asm volatile ("movq %q0,%%fs:%P1" :                                  \
257                        : IMM_MODE ((uint64_t) cast_to_integer (value)),       \
258                          "i" (offsetof (struct rthread, member)));            \
259        }})
260
261
262 /* Set member of the thread descriptor directly.  */
263 # define THREAD_SETMEM_NC(descr, member, idx, value) \
264   ({ if (sizeof (descr->member[0]) == 1)                                      \
265        asm volatile ("movb %b0,%%fs:%P1(%q2)" :                               \
266                      : "iq" (value),                                          \
267                        "i" (offsetof (struct rthread, member[0])),            \
268                        "r" (idx));                                            \
269      else if (sizeof (descr->member[0]) == 4)                                 \
270        asm volatile ("movl %0,%%fs:%P1(,%q2,4)" :                             \
271                      : IMM_MODE (value),                                      \
272                        "i" (offsetof (struct rthread, member[0])),            \
273                        "r" (idx));                                            \
274      else                                                                     \
275        {                                                                      \
276          if (sizeof (descr->member[0]) != 8)                                  \
277            /* There should not be any value with a size other than 1,         \
278               4 or 8.  */                                                     \
279            abort ();                                                          \
280                                                                               \
281          asm volatile ("movq %q0,%%fs:%P1(,%q2,8)" :                          \
282                        : IMM_MODE ((uint64_t) cast_to_integer (value)),       \
283                          "i" (offsetof (struct rthread, member[0])),          \
284                          "r" (idx));                                          \
285        }})
286
287
288 /* Atomic compare and exchange on TLS, returning old value.  */
289 # define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \
290   ({ __typeof (descr->member) __ret;                                          \
291      __typeof (oldval) __old = (oldval);                                      \
292      if (sizeof (descr->member) == 4)                                         \
293        asm volatile (LOCK_PREFIX "cmpxchgl %2, %%fs:%P3"                      \
294                      : "=a" (__ret)                                           \
295                      : "0" (__old), "r" (newval),                             \
296                        "i" (offsetof (struct rthread, member)));              \
297      else                                                                     \
298        /* Not necessary for other sizes in the moment.  */                    \
299        abort ();                                                              \
300      __ret; })
301
302
303 /* Atomic logical and.  */
304 # define THREAD_ATOMIC_AND(descr, member, val) \
305   (void) ({ if (sizeof ((descr)->member) == 4)                                \
306               asm volatile (LOCK_PREFIX "andl %1, %%fs:%P0"                   \
307                             :: "i" (offsetof (struct rthread, member)),       \
308                                "ir" (val));                                   \
309             else                                                              \
310               /* Not necessary for other sizes in the moment.  */             \
311               abort (); })
312
313
314 /* Atomic set bit.  */
315 # define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
316   (void) ({ if (sizeof ((descr)->member) == 4)                                \
317               asm volatile (LOCK_PREFIX "orl %1, %%fs:%P0"                    \
318                             :: "i" (offsetof (struct rthread, member)),       \
319                                "ir" (1 << (bit)));                            \
320             else                                                              \
321               /* Not necessary for other sizes in the moment.  */             \
322               abort (); })
323
324
325 # define CALL_THREAD_FCT(descr) \
326   ({ void *__res;                                                             \
327      asm volatile ("movq %%fs:%P2, %%rdi\n\t"                                 \
328                    "callq *%%fs:%P1"                                          \
329                    : "=a" (__res)                                             \
330                    : "i" (offsetof (struct rthread, start_routine)),          \
331                      "i" (offsetof (struct rthread, arg))                     \
332                    : "di", "si", "cx", "dx", "r8", "r9", "r10", "r11",        \
333                      "memory", "cc");                                         \
334      __res; })
335
336
337 /* Set the stack guard field in TCB head.  */
338 # define THREAD_SET_STACK_GUARD(value) \
339     THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
340 # define THREAD_COPY_STACK_GUARD(descr) \
341     ((descr)->header.stack_guard                                                  \
342      = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
343
344
345 /* Set the pointer guard field in the TCB head.  */
346 # define THREAD_SET_POINTER_GUARD(value) \
347   THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value)
348 # define THREAD_COPY_POINTER_GUARD(descr) \
349   ((descr)->header.pointer_guard                                              \
350    = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
351
352
353 /* Get and set the global scope generation counter in the TCB head.  */
354 # define THREAD_GSCOPE_FLAG_UNUSED 0
355 # define THREAD_GSCOPE_FLAG_USED   1
356 # define THREAD_GSCOPE_FLAG_WAIT   2
357 # define THREAD_GSCOPE_RESET_FLAG() \
358   do                                                                          \
359     { int __res;                                                              \
360       asm volatile ("xchgl %0, %%fs:%P1"                                      \
361                     : "=r" (__res)                                            \
362                     : "i" (offsetof (struct rthread, header.gscope_flag)),    \
363                       "0" (THREAD_GSCOPE_FLAG_UNUSED));                       \
364       if (__res == THREAD_GSCOPE_FLAG_WAIT)                                   \
365         lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);    \
366     }                                                                         \
367   while (0)
368 # define THREAD_GSCOPE_SET_FLAG() \
369   THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
370 # define THREAD_GSCOPE_WAIT() \
371   GL(dl_wait_lookup_done) ()
372
373
374 # ifdef SHARED
375 /* Defined in dl-trampoline.S.  */
376 extern void _dl_x86_64_save_sse (void);
377 extern void _dl_x86_64_restore_sse (void);
378
379 # define RTLD_CHECK_FOREIGN_CALL \
380   (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save) != 0)
381
382 /* NB: Don't use the xchg operation because that would imply a lock
383    prefix which is expensive and unnecessary.  The cache line is also
384    not contested at all.  */
385 #  define RTLD_ENABLE_FOREIGN_CALL \
386   int old_rtld_must_xmm_save = THREAD_GETMEM (THREAD_SELF,                    \
387                                               header.rtld_must_xmm_save);     \
388   THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, 1)
389
390 #  define RTLD_PREPARE_FOREIGN_CALL \
391   do if (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save))              \
392     {                                                                         \
393       _dl_x86_64_save_sse ();                                                 \
394       THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, 0);              \
395     }                                                                         \
396   while (0)
397
398 #  define RTLD_FINALIZE_FOREIGN_CALL \
399   do {                                                                        \
400     if (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save) == 0)          \
401       _dl_x86_64_restore_sse ();                                              \
402     THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save,                    \
403                    old_rtld_must_xmm_save);                                   \
404   } while (0)
405 # endif
406
407 static inline void *__get_tls_desc(uint32_t vcoreid)
408 {
409         /* the tcb->self pointer is set to the TLS base address */
410         return THREAD_SELF;
411 }
412
413 static inline void __set_tls_desc(void *tls_desc, uint32_t vcoreid)
414 {
415         /* TODO: check for and use WRFSBASE */
416         __fastcall_setfsbase((uintptr_t)tls_desc);
417 }
418
419 static inline const char* tls_init_tp(void* thrdescr)
420 {
421   // TCB lives at thrdescr.
422   // The TCB's head pointer points to itself :-)
423   tcbhead_t* head = (tcbhead_t*)thrdescr;
424   head->tcb = thrdescr;
425   head->self = thrdescr;
426
427   __set_tls_desc(thrdescr, 0x00dead00); /* we ignore vcoreid, pass gibberish */
428   return NULL;
429 }
430
431 #endif /* __ASSEMBLER__ */
432
433 #endif  /* tls.h */