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