Rename patches to -akaros instead of -ros
[akaros.git] / tools / compilers / gcc-glibc / glibc-2.14.1-akaros / sysdeps / akaros / i386 / tls.h
1 /* Definition for thread-local data handling.  nptl/i386 version.
2    Copyright (C) 2002-2007, 2009 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #ifndef _TLS_H
21 #define _TLS_H  1
22
23 #include <dl-sysdep.h>
24 #ifndef __ASSEMBLER__
25 # include <stdbool.h>
26 # include <stddef.h>
27 # include <stdint.h>
28 # include <stdlib.h>
29 //# include <list.h>
30 # include <sysdep.h>
31 # include <kernel-features.h>
32 #include <sys/mman.h>
33 #include <sys/syscall.h>
34 #include <ros/procinfo.h>
35 #include <ros/procdata.h>
36 #include <ros/arch/mmu.h>
37
38
39 /* Type for the dtv.  */
40 typedef union dtv
41 {
42   size_t counter;
43   struct
44   {
45     void *val;
46     bool is_static;
47   } pointer;
48 } dtv_t;
49
50
51 typedef struct
52 {
53   void *tcb;            /* Pointer to the TCB.  Not necessarily the
54                            thread descriptor used by libpthread.  */
55   dtv_t *dtv;
56   void *self;           /* Pointer to the thread descriptor.  */
57   int multiple_threads;
58   uintptr_t sysinfo;
59   uintptr_t stack_guard;
60   uintptr_t pointer_guard;
61   int gscope_flag;
62 #ifndef __ASSUME_PRIVATE_FUTEX
63   int private_futex;
64 #else
65   int __unused1;
66 #endif
67   /* Reservation of some values for the TM ABI.  */
68   void *__private_tm[5];
69 } tcbhead_t;
70
71 # define TLS_MULTIPLE_THREADS_IN_TCB 1
72
73 typedef struct rthread {
74     tcbhead_t header;
75 } rthread_t;
76
77 #else /* __ASSEMBLER__ */
78 //# include <tcb-offsets.h>
79 #endif
80
81
82 /* We require TLS support in the tools.  */
83 #ifndef HAVE_TLS_SUPPORT
84 # error "TLS support is required."
85 #endif
86
87 /* Alignment requirement for the stack.  For IA-32 this is governed by
88    the SSE memory functions.  */
89 #define STACK_ALIGN     16
90
91 #ifndef __ASSEMBLER__
92 /* Get system call information.  */
93 # include <sysdep.h>
94
95 /* The old way: using LDT.  */
96
97 /* Structure passed to `modify_ldt', 'set_thread_area', and 'clone' calls.  */
98 struct user_desc
99 {
100   unsigned int entry_number;
101   unsigned long int base_addr;
102   unsigned int limit;
103   unsigned int seg_32bit:1;
104   unsigned int contents:2;
105   unsigned int read_exec_only:1;
106   unsigned int limit_in_pages:1;
107   unsigned int seg_not_present:1;
108   unsigned int useable:1;
109   unsigned int empty:25;
110 };
111
112 /* Initializing bit fields is slow.  We speed it up by using a union.  */
113 union user_desc_init
114 {
115   struct user_desc desc;
116   unsigned int vals[4];
117 };
118
119
120 /* Get the thread descriptor definition.  */
121 //# include <nptl/descr.h>
122
123 /* This is the size of the initial TCB.  Can't be just sizeof (tcbhead_t),
124    because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole
125    struct rthread even when not linked with -lpthread.  */
126 # define TLS_INIT_TCB_SIZE sizeof (struct rthread)
127
128 /* Alignment requirements for the initial TCB.  */
129 # define TLS_INIT_TCB_ALIGN __alignof__ (struct rthread)
130
131 /* This is the size of the TCB.  */
132 # define TLS_TCB_SIZE sizeof (struct rthread)
133
134 /* Alignment requirements for the TCB.  */
135 # define TLS_TCB_ALIGN __alignof__ (struct rthread)
136
137 /* The TCB can have any size and the memory following the address the
138    thread pointer points to is unspecified.  Allocate the TCB there.  */
139 # define TLS_TCB_AT_TP  1
140
141
142 /* Install the dtv pointer.  The pointer passed is to the element with
143    index -1 which contain the length.  */
144 # define INSTALL_DTV(descr, dtvp) \
145   ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
146
147 /* Install new dtv for current thread.  */
148 # define INSTALL_NEW_DTV(dtvp) \
149   ({ struct rthread *__pd;                                                    \
150      THREAD_SETMEM (__pd, header.dtv, (dtvp)); })
151
152 /* Return dtv of given thread descriptor.  */
153 # define GET_DTV(descr) \
154   (((tcbhead_t *) (descr))->dtv)
155
156 #define THREAD_SELF_SYSINFO     THREAD_GETMEM (THREAD_SELF, header.sysinfo)
157 #define THREAD_SYSINFO(pd)      ((pd)->header.sysinfo)
158
159 /* Macros to load from and store into segment registers.  */
160 # ifndef TLS_GET_GS
161 #  define TLS_GET_GS() \
162   ({ int __seg; __asm ("movw %%gs, %w0" : "=q" (__seg)); __seg & 0xffff; })
163 # endif
164 # ifndef TLS_SET_GS
165 #  define TLS_SET_GS(val) \
166   __asm ("movw %w0, %%gs" :: "q" (val))
167 # endif
168
169
170 # ifndef __NR_set_thread_area
171 #  define __NR_set_thread_area 243
172 # endif
173 # ifndef TLS_FLAG_WRITABLE
174 #  define TLS_FLAG_WRITABLE             0x00000001
175 # endif
176
177 // XXX Enable for the real world.
178 #if 0
179 # ifndef __ASSUME_SET_THREAD_AREA
180 #  error "we need set_thread_area"
181 # endif
182 #endif
183
184 # ifdef __PIC__
185 #  define TLS_EBX_ARG "r"
186 #  define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t"
187 # else
188 #  define TLS_EBX_ARG "b"
189 #  define TLS_LOAD_EBX
190 # endif
191
192 #if defined NEED_DL_SYSINFO
193 # define INIT_SYSINFO \
194   _head->sysinfo = GLRO(dl_sysinfo)
195 #else
196 # define INIT_SYSINFO
197 #endif
198
199 #ifndef LOCK_PREFIX
200 # ifdef UP
201 #  define LOCK_PREFIX  /* nothing */
202 # else
203 #  define LOCK_PREFIX "lock;"
204 # endif
205 #endif
206
207 /* Code to initially initialize the thread pointer.  This might need
208    special attention since 'errno' is not yet available and if the
209    operation can cause a failure 'errno' must not be touched.  */
210 # define TLS_INIT_TP(thrdescr, secondcall) tls_init_tp(thrdescr)
211
212 /* Return the address of the dtv for the current thread.  */
213 # define THREAD_DTV() \
214   ({ struct rthread *__pd;                                                    \
215      THREAD_GETMEM (__pd, header.dtv); })
216
217
218 /* Return the thread descriptor for the current thread.
219
220    The contained asm must *not* be marked volatile since otherwise
221    assignments like
222         pthread_descr self = thread_self();
223    do not get optimized away.  */
224 # define THREAD_SELF \
225   ({ struct rthread *__self;                                                  \
226      asm ("movl %%gs:%c1,%0" : "=r" (__self)                                  \
227           : "i" (offsetof (struct rthread, header.self)));                    \
228      __self;})
229
230 /* Magic for libthread_db to know how to do THREAD_SELF.  */
231 # define DB_THREAD_SELF \
232   REGISTER_THREAD_AREA (32, offsetof (struct user_regs_struct, xgs), 3) \
233   REGISTER_THREAD_AREA (64, 26 * 8, 3) /* x86-64's user_regs_struct->gs */
234
235
236 /* Read member of the thread descriptor directly.  */
237 # define THREAD_GETMEM(descr, member) \
238   ({ __typeof (descr->member) __value;                                        \
239      if (sizeof (__value) == 1)                                               \
240        asm volatile ("movb %%gs:%P2,%b0"                                      \
241                      : "=q" (__value)                                         \
242                      : "0" (0), "i" (offsetof (struct rthread, member)));     \
243      else if (sizeof (__value) == 4)                                          \
244        asm volatile ("movl %%gs:%P1,%0"                                       \
245                      : "=r" (__value)                                         \
246                      : "i" (offsetof (struct rthread, member)));              \
247      else                                                                     \
248        {                                                                      \
249          if (sizeof (__value) != 8)                                           \
250            /* There should not be any value with a size other than 1,         \
251               4 or 8.  */                                                     \
252            abort ();                                                          \
253                                                                               \
254          asm volatile ("movl %%gs:%P1,%%eax\n\t"                              \
255                        "movl %%gs:%P2,%%edx"                                  \
256                        : "=A" (__value)                                       \
257                        : "i" (offsetof (struct rthread, member)),             \
258                          "i" (offsetof (struct rthread, member) + 4));        \
259        }                                                                      \
260      __value; })
261
262
263 /* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
264 # define THREAD_GETMEM_NC(descr, member, idx) \
265   ({ __typeof (descr->member[0]) __value;                                     \
266      if (sizeof (__value) == 1)                                               \
267        asm volatile ("movb %%gs:%P2(%3),%b0"                                  \
268                      : "=q" (__value)                                         \
269                      : "0" (0), "i" (offsetof (struct rthread, member[0])),   \
270                      "r" (idx));                                              \
271      else if (sizeof (__value) == 4)                                          \
272        asm volatile ("movl %%gs:%P1(,%2,4),%0"                                \
273                      : "=r" (__value)                                         \
274                      : "i" (offsetof (struct rthread, member[0])),            \
275                        "r" (idx));                                            \
276      else                                                                     \
277        {                                                                      \
278          if (sizeof (__value) != 8)                                           \
279            /* There should not be any value with a size other than 1,         \
280               4 or 8.  */                                                     \
281            abort ();                                                          \
282                                                                               \
283          asm volatile  ("movl %%gs:%P1(,%2,8),%%eax\n\t"                      \
284                         "movl %%gs:4+%P1(,%2,8),%%edx"                        \
285                         : "=&A" (__value)                                     \
286                         : "i" (offsetof (struct rthread, member[0])),         \
287                           "r" (idx));                                         \
288        }                                                                      \
289      __value; })
290
291
292 /* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
293 # define THREAD_SETMEM(descr, member, value) \
294   ({ if (sizeof (descr->member) == 1)                                         \
295        asm volatile ("movb %b0,%%gs:%P1" :                                    \
296                      : "iq" (value),                                          \
297                        "i" (offsetof (struct rthread, member)));              \
298      else if (sizeof (descr->member) == 4)                                    \
299        asm volatile ("movl %0,%%gs:%P1" :                                     \
300                      : "ir" (value),                                          \
301                        "i" (offsetof (struct rthread, member)));              \
302      else                                                                     \
303        {                                                                      \
304          if (sizeof (descr->member) != 8)                                     \
305            /* There should not be any value with a size other than 1,         \
306               4 or 8.  */                                                     \
307            abort ();                                                          \
308                                                                               \
309          asm volatile ("movl %%eax,%%gs:%P1\n\t"                              \
310                        "movl %%edx,%%gs:%P2" :                                \
311                        : "A" (value),                                         \
312                          "i" (offsetof (struct rthread, member)),             \
313                          "i" (offsetof (struct rthread, member) + 4));        \
314        }})
315
316
317 /* Set member of the thread descriptor directly.  */
318 # define THREAD_SETMEM_NC(descr, member, idx, value) \
319   ({ if (sizeof (descr->member[0]) == 1)                                      \
320        asm volatile ("movb %b0,%%gs:%P1(%2)" :                                \
321                      : "iq" (value),                                          \
322                        "i" (offsetof (struct rthread, member)),               \
323                        "r" (idx));                                            \
324      else if (sizeof (descr->member[0]) == 4)                                 \
325        asm volatile ("movl %0,%%gs:%P1(,%2,4)" :                              \
326                      : "ir" (value),                                          \
327                        "i" (offsetof (struct rthread, member)),               \
328                        "r" (idx));                                            \
329      else                                                                     \
330        {                                                                      \
331          if (sizeof (descr->member[0]) != 8)                                  \
332            /* There should not be any value with a size other than 1,         \
333               4 or 8.  */                                                     \
334            abort ();                                                          \
335                                                                               \
336          asm volatile ("movl %%eax,%%gs:%P1(,%2,8)\n\t"                       \
337                        "movl %%edx,%%gs:4+%P1(,%2,8)" :                       \
338                        : "A" (value),                                         \
339                          "i" (offsetof (struct rthread, member)),             \
340                          "r" (idx));                                          \
341        }})
342
343
344 /* Atomic compare and exchange on TLS, returning old value.  */
345 #define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \
346   ({ __typeof (descr->member) __ret;                                          \
347      __typeof (oldval) __old = (oldval);                                      \
348      if (sizeof (descr->member) == 4)                                         \
349        asm volatile (LOCK_PREFIX "cmpxchgl %2, %%gs:%P3"                      \
350                      : "=a" (__ret)                                           \
351                      : "0" (__old), "r" (newval),                             \
352                        "i" (offsetof (struct rthread, member)));              \
353      else                                                                     \
354        /* Not necessary for other sizes in the moment.  */                    \
355        abort ();                                                              \
356      __ret; })
357
358
359 /* Atomic logical and.  */
360 #define THREAD_ATOMIC_AND(descr, member, val) \
361   (void) ({ if (sizeof ((descr)->member) == 4)                                \
362               asm volatile (LOCK_PREFIX "andl %1, %%gs:%P0"                   \
363                             :: "i" (offsetof (struct rthread, member)),       \
364                                "ir" (val));                                   \
365             else                                                              \
366               /* Not necessary for other sizes in the moment.  */             \
367               abort (); })
368
369
370 /* Atomic set bit.  */
371 #define THREAD_ATOMIC_BIT_SET(descr, member, bit) \
372   (void) ({ if (sizeof ((descr)->member) == 4)                                \
373               asm volatile (LOCK_PREFIX "orl %1, %%gs:%P0"                    \
374                             :: "i" (offsetof (struct rthread, member)),       \
375                                "ir" (1 << (bit)));                            \
376             else                                                              \
377               /* Not necessary for other sizes in the moment.  */             \
378               abort (); })
379
380
381 /* Call the user-provided thread function.  */
382 #define CALL_THREAD_FCT(descr) \
383   ({ void *__res;                                                             \
384      int __ignore1, __ignore2;                                                \
385      asm volatile ("pushl %%eax\n\t"                                          \
386                    "pushl %%eax\n\t"                                          \
387                    "pushl %%eax\n\t"                                          \
388                    "pushl %%gs:%P4\n\t"                                       \
389                    "call *%%gs:%P3\n\t"                                       \
390                    "addl $16, %%esp"                                          \
391                    : "=a" (__res), "=c" (__ignore1), "=d" (__ignore2)         \
392                    : "i" (offsetof (struct rthread, start_routine)),          \
393                      "i" (offsetof (struct rthread, arg)));                   \
394      __res; })
395
396
397 /* Set the stack guard field in TCB head.  */
398 #define THREAD_SET_STACK_GUARD(value) \
399   THREAD_SETMEM (THREAD_SELF, header.stack_guard, value)
400 #define THREAD_COPY_STACK_GUARD(descr) \
401   ((descr)->header.stack_guard                                                \
402    = THREAD_GETMEM (THREAD_SELF, header.stack_guard))
403
404
405 /* Set the pointer guard field in the TCB head.  */
406 #define THREAD_SET_POINTER_GUARD(value) \
407   THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value)
408 #define THREAD_COPY_POINTER_GUARD(descr) \
409   ((descr)->header.pointer_guard                                              \
410    = THREAD_GETMEM (THREAD_SELF, header.pointer_guard))
411
412
413 /* Get and set the global scope generation counter in the TCB head.  */
414 #define THREAD_GSCOPE_FLAG_UNUSED 0
415 #define THREAD_GSCOPE_FLAG_USED   1
416 #define THREAD_GSCOPE_FLAG_WAIT   2
417 #define THREAD_GSCOPE_RESET_FLAG() \
418   do                                                                          \
419     { int __res;                                                              \
420       asm volatile ("xchgl %0, %%gs:%P1"                                      \
421                     : "=r" (__res)                                            \
422                     : "i" (offsetof (struct rthread, header.gscope_flag)),    \
423                       "0" (THREAD_GSCOPE_FLAG_UNUSED));                       \
424       if (__res == THREAD_GSCOPE_FLAG_WAIT)                                   \
425         lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);    \
426     }                                                                         \
427   while (0)
428 #define THREAD_GSCOPE_SET_FLAG() \
429   THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED)
430 #define THREAD_GSCOPE_WAIT() \
431   GL(dl_wait_lookup_done) ()
432
433 /* Reading from the LDT.  Could also use %gs, but that would require including
434  * half of libc's TLS header.  Sparc will probably ignore the vcoreid, so don't
435  * rely on it too much.  The intent of it is vcoreid is the caller's vcoreid,
436  * and that vcoreid might be in the TLS of the caller (it will be for transition
437  * stacks) and we could avoid a trap on x86 to sys_getvcoreid(). */
438 static inline void *__get_tls_desc(uint32_t vcoreid)
439 {
440         return (void*)(__procdata.ldt[vcoreid].sd_base_31_24 << 24 |
441                        __procdata.ldt[vcoreid].sd_base_23_16 << 16 |
442                        __procdata.ldt[vcoreid].sd_base_15_0);
443 }
444
445 /* passing in the vcoreid, since it'll be in TLS of the caller */
446 static inline void __set_tls_desc(void *tls_desc, uint32_t vcoreid)
447 {
448         /* Keep this technique in sync with sysdeps/akaros/i386/tls.h */
449         segdesc_t tmp = SEG(STA_W, (uint32_t)tls_desc, 0xffffffff, 3);
450         __procdata.ldt[vcoreid] = tmp;
451
452         /* GS is still the same (should be!), but it needs to be reloaded to force a
453          * re-read of the LDT. */
454         uint32_t gs = (vcoreid << 3) | 0x07;
455         asm volatile("movl %0,%%gs" : : "r" (gs) : "memory");
456 }
457
458 static const char* tls_init_tp(void* thrdescr)
459 {
460   // TCB lives at thrdescr.
461   // The TCB's head pointer points to itself :-)
462   tcbhead_t* head = (tcbhead_t*)thrdescr;
463   head->tcb = thrdescr;
464   head->self = thrdescr;
465
466   //TODO: think about how to avoid this. Probably add a field to the 
467   // rthreads struct that we manually fill in in _start(). 
468   int core_id = __ros_syscall_noerrno(SYS_getvcoreid, 0, 0, 0, 0, 0, 0);
469
470   /* Bug with this whole idea (TODO: (TLSV))*/
471   if(__procdata.ldt == NULL)
472   {
473     size_t sz= (sizeof(segdesc_t)*__procinfo.max_vcores+PGSIZE-1)/PGSIZE*PGSIZE;
474     
475         /* Can't directly call mmap because it tries to set errno, and errno doesn't
476          * exist yet (it relies on tls, and we are currently in the process of
477          * setting it up...) */
478         void *ldt = (void*)__ros_syscall_noerrno(SYS_mmap, 0, sz,
479                                                  PROT_READ | PROT_WRITE,
480                                                  MAP_ANONYMOUS | MAP_POPULATE,
481                                                  -1, 0);
482     if (ldt == MAP_FAILED)
483       return "tls couldn't allocate memory\n";
484
485     __procdata.ldt = ldt;
486     // force kernel crossing
487         __ros_syscall_noerrno(SYS_getpid, 0, 0, 0, 0, 0, 0);
488   }
489
490   __set_tls_desc(thrdescr, core_id);
491   return NULL;
492 }
493
494 #endif /* __ASSEMBLER__ */
495
496 #endif  /* tls.h */