Prepare for 2.3.3-57
[glibc.git] / linuxthreads / sysdeps / i386 / useldt.h
blob9a898ede744a6185117cf067a1a75ae7180c0cae
1 /* Special definitions for ix86 machine using segment register based
2 thread descriptor.
3 Copyright (C) 1998, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5 Contributed by Ulrich Drepper <drepper@cygnus.com>.
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.
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.
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 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 #ifndef __USELDT_H
23 #define __USELDT_H 1
25 #ifndef __ASSEMBLER__
26 #include <stddef.h> /* For offsetof. */
27 #include <stdlib.h> /* For abort(). */
28 #include <sysdep.h>
31 /* We don't want to include the kernel header. So duplicate the
32 information. */
34 /* Structure passed on `modify_ldt' call. */
35 struct modify_ldt_ldt_s
37 unsigned int entry_number;
38 unsigned long int base_addr;
39 unsigned int limit;
40 unsigned int seg_32bit:1;
41 unsigned int contents:2;
42 unsigned int read_exec_only:1;
43 unsigned int limit_in_pages:1;
44 unsigned int seg_not_present:1;
45 unsigned int useable:1;
46 unsigned int empty:25;
49 /* System call to set LDT entry. */
50 extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
53 /* Return the thread descriptor for the current thread.
55 The contained asm must *not* be marked volatile since otherwise
56 assignments like
57 pthread_descr self = thread_self();
58 do not get optimized away. */
59 #define THREAD_SELF \
60 ({ \
61 register pthread_descr __self; \
62 __asm__ ("movl %%gs:%c1,%0" : "=r" (__self) \
63 : "i" (offsetof (struct _pthread_descr_struct, \
64 p_header.data.self))); \
65 __self; \
69 /* Initialize the thread-unique value. Two possible ways to do it. */
71 #define DO_MODIFY_LDT(descr, nr) \
72 ({ \
73 struct modify_ldt_ldt_s ldt_entry = \
74 { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
75 1, 0, 0, 1, 0, 1, 0 }; \
76 if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) \
77 abort (); \
78 asm ("movw %w0, %%gs" : : "q" (nr * 8 + 7)); \
81 #ifdef __PIC__
82 # define USETLS_EBX_ARG "r"
83 # define USETLS_LOAD_EBX "xchgl %1, %%ebx\n\t"
84 #else
85 # define USETLS_EBX_ARG "b"
86 # define USETLS_LOAD_EBX
87 #endif
89 /* When using the new set_thread_area call, we don't need to change %gs
90 because we inherited the value set up in the main thread by TLS setup.
91 We need to extract that value and set up the same segment in this
92 thread. */
93 #if USE_TLS
94 # define DO_SET_THREAD_AREA_REUSE(nr) 1
95 #else
96 /* Without TLS, we do the initialization of the main thread, where NR == 0. */
97 # define DO_SET_THREAD_AREA_REUSE(nr) (!__builtin_constant_p (nr) || (nr))
98 #endif
99 #define DO_SET_THREAD_AREA(descr, nr) \
100 ({ \
101 int __gs; \
102 if (DO_SET_THREAD_AREA_REUSE (nr)) \
104 asm ("movw %%gs, %w0" : "=q" (__gs)); \
105 struct modify_ldt_ldt_s ldt_entry = \
106 { (__gs & 0xffff) >> 3, \
107 (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
108 1, 0, 0, 1, 0, 1, 0 }; \
110 int __result; \
111 __asm (USETLS_LOAD_EBX \
112 "movl %2, %%eax\n\t" \
113 "int $0x80\n\t" \
114 USETLS_LOAD_EBX \
115 : "=&a" (__result) \
116 : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area), \
117 "m" (ldt_entry) \
118 : "memory"); \
119 if (__result == 0) \
120 asm ("movw %w0, %%gs" :: "q" (__gs)); \
121 else \
122 __gs = -1; \
124 else \
126 struct modify_ldt_ldt_s ldt_entry = \
127 { -1, \
128 (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \
129 1, 0, 0, 1, 0, 1, 0 }; \
130 int __result; \
131 __asm (USETLS_LOAD_EBX \
132 "movl %2, %%eax\n\t" \
133 "int $0x80\n\t" \
134 USETLS_LOAD_EBX \
135 : "=&a" (__result) \
136 : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area), \
137 "m" (ldt_entry) \
138 : "memory"); \
139 if (__result == 0) \
141 __gs = (ldt_entry.entry_number << 3) + 3; \
142 asm ("movw %w0, %%gs" : : "q" (__gs)); \
144 else \
145 __gs = -1; \
147 __gs; \
150 #if defined __ASSUME_SET_THREAD_AREA_SYSCALL
151 # define INIT_THREAD_SELF(descr, nr) DO_SET_THREAD_AREA (descr, nr)
152 #elif defined __NR_set_thread_area
153 # define INIT_THREAD_SELF(descr, nr) \
154 ({ \
155 if (__builtin_expect (__have_no_set_thread_area, 0) \
156 || (DO_SET_THREAD_AREA (descr, DO_SET_THREAD_AREA_REUSE (nr)) == -1 \
157 && (__have_no_set_thread_area = 1))) \
158 DO_MODIFY_LDT (descr, nr); \
160 /* Defined in pspinlock.c. */
161 extern int __have_no_set_thread_area;
162 #else
163 # define INIT_THREAD_SELF(descr, nr) DO_MODIFY_LDT (descr, nr)
164 #endif
166 /* Free resources associated with thread descriptor. */
167 #ifdef __ASSUME_SET_THREAD_AREA_SYSCALL
168 #define FREE_THREAD(descr, nr) do { } while (0)
169 #elif defined __NR_set_thread_area
170 #define FREE_THREAD(descr, nr) \
172 int __gs; \
173 __asm__ __volatile__ ("movw %%gs, %w0" : "=q" (__gs)); \
174 if (__builtin_expect (__gs & 4, 0)) \
176 struct modify_ldt_ldt_s ldt_entry = \
177 { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \
178 __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \
181 #else
182 #define FREE_THREAD(descr, nr) \
184 struct modify_ldt_ldt_s ldt_entry = \
185 { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \
186 __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \
188 #endif
190 /* Read member of the thread descriptor directly. */
191 #define THREAD_GETMEM(descr, member) \
192 ({ \
193 __typeof__ (descr->member) __value; \
194 if (sizeof (__value) == 1) \
195 __asm__ __volatile__ ("movb %%gs:%P2,%b0" \
196 : "=q" (__value) \
197 : "0" (0), \
198 "i" (offsetof (struct _pthread_descr_struct, \
199 member))); \
200 else if (sizeof (__value) == 4) \
201 __asm__ __volatile__ ("movl %%gs:%P1,%0" \
202 : "=r" (__value) \
203 : "i" (offsetof (struct _pthread_descr_struct, \
204 member))); \
205 else \
207 if (sizeof (__value) != 8) \
208 /* There should not be any value with a size other than 1, 4 or 8. */\
209 abort (); \
211 __asm__ __volatile__ ("movl %%gs:%P1,%%eax\n\t" \
212 "movl %%gs:%P2,%%edx" \
213 : "=A" (__value) \
214 : "i" (offsetof (struct _pthread_descr_struct, \
215 member)), \
216 "i" (offsetof (struct _pthread_descr_struct, \
217 member) + 4)); \
219 __value; \
222 /* Same as THREAD_GETMEM, but the member offset can be non-constant. */
223 #define THREAD_GETMEM_NC(descr, member) \
224 ({ \
225 __typeof__ (descr->member) __value; \
226 if (sizeof (__value) == 1) \
227 __asm__ __volatile__ ("movb %%gs:(%2),%b0" \
228 : "=q" (__value) \
229 : "0" (0), \
230 "r" (offsetof (struct _pthread_descr_struct, \
231 member))); \
232 else if (sizeof (__value) == 4) \
233 __asm__ __volatile__ ("movl %%gs:(%1),%0" \
234 : "=r" (__value) \
235 : "r" (offsetof (struct _pthread_descr_struct, \
236 member))); \
237 else \
239 if (sizeof (__value) != 8) \
240 /* There should not be any value with a size other than 1, 4 or 8. */\
241 abort (); \
243 __asm__ __volatile__ ("movl %%gs:(%1),%%eax\n\t" \
244 "movl %%gs:4(%1),%%edx" \
245 : "=&A" (__value) \
246 : "r" (offsetof (struct _pthread_descr_struct, \
247 member))); \
249 __value; \
252 /* Same as THREAD_SETMEM, but the member offset can be non-constant. */
253 #define THREAD_SETMEM(descr, member, value) \
254 ({ \
255 __typeof__ (descr->member) __value = (value); \
256 if (sizeof (__value) == 1) \
257 __asm__ __volatile__ ("movb %0,%%gs:%P1" : \
258 : "q" (__value), \
259 "i" (offsetof (struct _pthread_descr_struct, \
260 member))); \
261 else if (sizeof (__value) == 4) \
262 __asm__ __volatile__ ("movl %0,%%gs:%P1" : \
263 : "r" (__value), \
264 "i" (offsetof (struct _pthread_descr_struct, \
265 member))); \
266 else \
268 if (sizeof (__value) != 8) \
269 /* There should not be any value with a size other than 1, 4 or 8. */\
270 abort (); \
272 __asm__ __volatile__ ("movl %%eax,%%gs:%P1\n\n" \
273 "movl %%edx,%%gs:%P2" : \
274 : "A" (__value), \
275 "i" (offsetof (struct _pthread_descr_struct, \
276 member)), \
277 "i" (offsetof (struct _pthread_descr_struct, \
278 member) + 4)); \
282 /* Set member of the thread descriptor directly. */
283 #define THREAD_SETMEM_NC(descr, member, value) \
284 ({ \
285 __typeof__ (descr->member) __value = (value); \
286 if (sizeof (__value) == 1) \
287 __asm__ __volatile__ ("movb %0,%%gs:(%1)" : \
288 : "q" (__value), \
289 "r" (offsetof (struct _pthread_descr_struct, \
290 member))); \
291 else if (sizeof (__value) == 4) \
292 __asm__ __volatile__ ("movl %0,%%gs:(%1)" : \
293 : "r" (__value), \
294 "r" (offsetof (struct _pthread_descr_struct, \
295 member))); \
296 else \
298 if (sizeof (__value) != 8) \
299 /* There should not be any value with a size other than 1, 4 or 8. */\
300 abort (); \
302 __asm__ __volatile__ ("movl %%eax,%%gs:(%1)\n\t" \
303 "movl %%edx,%%gs:4(%1)" : \
304 : "A" (__value), \
305 "r" (offsetof (struct _pthread_descr_struct, \
306 member))); \
309 #endif
311 #if __ASSUME_LDT_WORKS > 0
312 /* We want the OS to assign stack addresses. */
313 #define FLOATING_STACKS 1
315 /* Maximum size of the stack if the rlimit is unlimited. */
316 #define ARCH_STACK_MAX_SIZE 8*1024*1024
317 #endif
319 #endif