]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libpthread/linuxthreads/sysdeps/i386/useldt.h
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libpthread / linuxthreads / sysdeps / i386 / useldt.h
1 /* Special definitions for ix86 machine using segment register based
2    thread descriptor.
3    Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Ulrich Drepper <drepper@cygnus.com>.
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of the
10    License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; see the file COPYING.LIB.  If not,
19    see <http://www.gnu.org/licenses/>.  */
20
21 #ifndef __ASSEMBLER__
22 #include <stddef.h>     /* For offsetof.  */
23 #include <stdlib.h>     /* For abort().  */
24 #include <sysdep.h>
25
26
27 /* We don't want to include the kernel header.  So duplicate the
28    information.  */
29
30 /* Structure passed on `modify_ldt' call.  */
31 struct modify_ldt_ldt_s
32 {
33   unsigned int entry_number;
34   unsigned long int base_addr;
35   unsigned int limit;
36   unsigned int seg_32bit:1;
37   unsigned int contents:2;
38   unsigned int read_exec_only:1;
39   unsigned int limit_in_pages:1;
40   unsigned int seg_not_present:1;
41   unsigned int useable:1;
42   unsigned int empty:25;
43 };
44
45 /* System call to set LDT entry.  */
46 extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
47
48
49 /* Return the thread descriptor for the current thread.
50
51    The contained asm must *not* be marked volatile since otherwise
52    assignments like
53         pthread_descr self = thread_self();
54    do not get optimized away.  */
55 #define THREAD_SELF \
56 ({                                                                            \
57   register pthread_descr __self;                                              \
58   __asm__ ("movl %%gs:%c1,%0" : "=r" (__self)                                 \
59            : "i" (offsetof (struct _pthread_descr_struct,                     \
60                             p_header.data.self)));                            \
61   __self;                                                                     \
62 })
63
64
65 /* Initialize the thread-unique value.  Two possible ways to do it.  */
66
67 #define DO_MODIFY_LDT(descr, nr)                                              \
68 ({                                                                            \
69   struct modify_ldt_ldt_s ldt_entry =                                         \
70     { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */,            \
71       1, 0, 0, 1, 0, 1, 0 };                                                  \
72   if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0)                  \
73     abort ();                                                                 \
74   __asm__ ("movw %w0, %%gs" : : "q" (nr * 8 + 7));                                    \
75 })
76
77 #ifdef __PIC__
78 # define USETLS_EBX_ARG "r"
79 # define USETLS_LOAD_EBX "xchgl %1, %%ebx\n\t"
80 #else
81 # define USETLS_EBX_ARG "b"
82 # define USETLS_LOAD_EBX
83 #endif
84
85 /* When using the new set_thread_area call, we don't need to change %gs
86    because we inherited the value set up in the main thread by TLS setup.
87    We need to extract that value and set up the same segment in this
88    thread.  */
89 #ifdef __UCLIBC_HAS_TLS__
90 # define DO_SET_THREAD_AREA_REUSE(nr)   1
91 #else
92 /* Without TLS, we do the initialization of the main thread, where NR == 0.  */
93 # define DO_SET_THREAD_AREA_REUSE(nr)   (!__builtin_constant_p (nr) || (nr))
94 #endif
95 #define DO_SET_THREAD_AREA(descr, nr) \
96 ({                                                                            \
97   int __gs;                                                                   \
98   if (DO_SET_THREAD_AREA_REUSE (nr))                                          \
99     {                                                                         \
100       __asm__ ("movw %%gs, %w0" : "=q" (__gs));                               \
101       struct modify_ldt_ldt_s ldt_entry =                                     \
102         { (__gs & 0xffff) >> 3,                                               \
103           (unsigned long int) (descr), 0xfffff /* 4GB in pages */,            \
104           1, 0, 0, 1, 0, 1, 0 };                                              \
105                                                                               \
106       int __result;                                                           \
107       __asm__ (USETLS_LOAD_EBX                                                \
108              "movl %2, %%eax\n\t"                                             \
109              "int $0x80\n\t"                                                  \
110              USETLS_LOAD_EBX                                                  \
111              : "=&a" (__result)                                               \
112              : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area),       \
113                "m" (ldt_entry)                                                \
114              : "memory");                                                     \
115       if (__result == 0)                                                      \
116         __asm__ ("movw %w0, %%gs" :: "q" (__gs));                                     \
117       else                                                                    \
118         __gs = -1;                                                            \
119     }                                                                         \
120   else                                                                        \
121     {                                                                         \
122       struct modify_ldt_ldt_s ldt_entry =                                     \
123         { -1,                                                                 \
124           (unsigned long int) (descr), 0xfffff /* 4GB in pages */,            \
125           1, 0, 0, 1, 0, 1, 0 };                                              \
126       int __result;                                                           \
127       __asm__ (USETLS_LOAD_EBX                                                \
128              "movl %2, %%eax\n\t"                                             \
129              "int $0x80\n\t"                                                  \
130              USETLS_LOAD_EBX                                                  \
131              : "=&a" (__result)                                               \
132              : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area),       \
133                "m" (ldt_entry)                                                \
134              : "memory");                                                     \
135       if (__result == 0)                                                      \
136         {                                                                     \
137           __gs = (ldt_entry.entry_number << 3) + 3;                           \
138           __asm__ ("movw %w0, %%gs" : : "q" (__gs));                          \
139         }                                                                     \
140       else                                                                    \
141         __gs = -1;                                                            \
142     }                                                                         \
143   __gs;                                                                       \
144 })
145
146 #if defined __ASSUME_SET_THREAD_AREA_SYSCALL
147 # define INIT_THREAD_SELF(descr, nr)    DO_SET_THREAD_AREA (descr, nr)
148 #elif defined __NR_set_thread_area
149 # define INIT_THREAD_SELF(descr, nr)                                          \
150 ({                                                                            \
151   if (__builtin_expect (__have_no_set_thread_area, 0)                         \
152       || (DO_SET_THREAD_AREA (descr, DO_SET_THREAD_AREA_REUSE (nr)) == -1     \
153           && (__have_no_set_thread_area = 1)))                                \
154     DO_MODIFY_LDT (descr, nr);                                                \
155 })
156 /* Defined in pspinlock.c.  */
157 extern int __have_no_set_thread_area;
158 #else
159 # define INIT_THREAD_SELF(descr, nr)    DO_MODIFY_LDT (descr, nr)
160 #endif
161
162 /* Free resources associated with thread descriptor.  */
163 #ifdef __ASSUME_SET_THREAD_AREA_SYSCALL
164 #define FREE_THREAD(descr, nr) do { } while (0)
165 #elif defined __NR_set_thread_area
166 #define FREE_THREAD(descr, nr) \
167 {                                                                             \
168   int __gs;                                                                   \
169   __asm__ __volatile__ ("movw %%gs, %w0" : "=q" (__gs));                      \
170   if (__builtin_expect (__gs & 4, 0))                                         \
171     {                                                                         \
172       struct modify_ldt_ldt_s ldt_entry =                                     \
173         { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 };                                    \
174       __modify_ldt (1, &ldt_entry, sizeof (ldt_entry));                       \
175     }                                                                         \
176 }
177 #else
178 #define FREE_THREAD(descr, nr) \
179 {                                                                             \
180   struct modify_ldt_ldt_s ldt_entry =                                         \
181     { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 };                                        \
182   __modify_ldt (1, &ldt_entry, sizeof (ldt_entry));                           \
183 }
184 #endif
185
186 /* Read member of the thread descriptor directly.  */
187 #define THREAD_GETMEM(descr, member) \
188 ({                                                                            \
189   __typeof__ (descr->member) __value;                                         \
190   if (sizeof (__value) == 1)                                                  \
191     __asm__ __volatile__ ("movb %%gs:%P2,%b0"                                 \
192                           : "=q" (__value)                                    \
193                           : "0" (0),                                          \
194                             "i" (offsetof (struct _pthread_descr_struct,      \
195                                            member)));                         \
196   else if (sizeof (__value) == 4)                                             \
197     __asm__ __volatile__ ("movl %%gs:%P1,%0"                                  \
198                           : "=r" (__value)                                    \
199                           : "i" (offsetof (struct _pthread_descr_struct,      \
200                                            member)));                         \
201   else                                                                        \
202     {                                                                         \
203       if (sizeof (__value) != 8)                                              \
204         /* There should not be any value with a size other than 1, 4 or 8.  */\
205         abort ();                                                             \
206                                                                               \
207       __asm__ __volatile__ ("movl %%gs:%P1,%%eax\n\t"                         \
208                             "movl %%gs:%P2,%%edx"                             \
209                             : "=A" (__value)                                  \
210                             : "i" (offsetof (struct _pthread_descr_struct,    \
211                                              member)),                        \
212                               "i" (offsetof (struct _pthread_descr_struct,    \
213                                              member) + 4));                   \
214     }                                                                         \
215   __value;                                                                    \
216 })
217
218 /* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
219 #define THREAD_GETMEM_NC(descr, member) \
220 ({                                                                            \
221   __typeof__ (descr->member) __value;                                         \
222   if (sizeof (__value) == 1)                                                  \
223     __asm__ __volatile__ ("movb %%gs:(%2),%b0"                                \
224                           : "=q" (__value)                                    \
225                           : "0" (0),                                          \
226                             "r" (offsetof (struct _pthread_descr_struct,      \
227                                            member)));                         \
228   else if (sizeof (__value) == 4)                                             \
229     __asm__ __volatile__ ("movl %%gs:(%1),%0"                                 \
230                           : "=r" (__value)                                    \
231                           : "r" (offsetof (struct _pthread_descr_struct,      \
232                                            member)));                         \
233   else                                                                        \
234     {                                                                         \
235       if (sizeof (__value) != 8)                                              \
236         /* There should not be any value with a size other than 1, 4 or 8.  */\
237         abort ();                                                             \
238                                                                               \
239       __asm__ __volatile__ ("movl %%gs:(%1),%%eax\n\t"                        \
240                             "movl %%gs:4(%1),%%edx"                           \
241                             : "=&A" (__value)                                 \
242                             : "r" (offsetof (struct _pthread_descr_struct,    \
243                                              member)));                       \
244     }                                                                         \
245   __value;                                                                    \
246 })
247
248 /* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
249 #define THREAD_SETMEM(descr, member, value) \
250 ({                                                                            \
251   __typeof__ (descr->member) __value = (value);                               \
252   if (sizeof (__value) == 1)                                                  \
253     __asm__ __volatile__ ("movb %0,%%gs:%P1" :                                \
254                           : "q" (__value),                                    \
255                             "i" (offsetof (struct _pthread_descr_struct,      \
256                                            member)));                         \
257   else if (sizeof (__value) == 4)                                             \
258     __asm__ __volatile__ ("movl %0,%%gs:%P1" :                                \
259                           : "r" (__value),                                    \
260                             "i" (offsetof (struct _pthread_descr_struct,      \
261                                            member)));                         \
262   else                                                                        \
263     {                                                                         \
264       if (sizeof (__value) != 8)                                              \
265         /* There should not be any value with a size other than 1, 4 or 8.  */\
266         abort ();                                                             \
267                                                                               \
268       __asm__ __volatile__ ("movl %%eax,%%gs:%P1\n\n"                         \
269                             "movl %%edx,%%gs:%P2" :                           \
270                             : "A" (__value),                                  \
271                               "i" (offsetof (struct _pthread_descr_struct,    \
272                                              member)),                        \
273                               "i" (offsetof (struct _pthread_descr_struct,    \
274                                              member) + 4));                   \
275     }                                                                         \
276 })
277
278 /* Set member of the thread descriptor directly.  */
279 #define THREAD_SETMEM_NC(descr, member, value) \
280 ({                                                                            \
281   __typeof__ (descr->member) __value = (value);                               \
282   if (sizeof (__value) == 1)                                                  \
283     __asm__ __volatile__ ("movb %0,%%gs:(%1)" :                               \
284                           : "q" (__value),                                    \
285                             "r" (offsetof (struct _pthread_descr_struct,      \
286                                            member)));                         \
287   else if (sizeof (__value) == 4)                                             \
288     __asm__ __volatile__ ("movl %0,%%gs:(%1)" :                               \
289                           : "r" (__value),                                    \
290                             "r" (offsetof (struct _pthread_descr_struct,      \
291                                            member)));                         \
292   else                                                                        \
293     {                                                                         \
294       if (sizeof (__value) != 8)                                              \
295         /* There should not be any value with a size other than 1, 4 or 8.  */\
296         abort ();                                                             \
297                                                                               \
298       __asm__ __volatile__ ("movl %%eax,%%gs:(%1)\n\t"                        \
299                             "movl %%edx,%%gs:4(%1)" :                         \
300                             : "A" (__value),                                  \
301                               "r" (offsetof (struct _pthread_descr_struct,    \
302                                              member)));                       \
303     }                                                                         \
304 })
305 #endif
306
307 #if __ASSUME_LDT_WORKS > 0
308 /* We want the OS to assign stack addresses.  */
309 #define FLOATING_STACKS 1
310
311 /* Maximum size of the stack if the rlimit is unlimited.  */
312 #define ARCH_STACK_MAX_SIZE     8*1024*1024
313 #endif