02d079c9ef59faac15511acfea39b9a5d369a8ea
[platform/upstream/glibc.git] / linuxthreads / sysdeps / i386 / useldt.h
1 /* Special definitions for ix86 machine using segment register based
2    thread descriptor.
3    Copyright (C) 1998, 2000, 2001 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 Library General Public License as
9    published by the Free Software Foundation; either version 2 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    Library General Public License for more details.
16
17    You should have received a copy of the GNU Library 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.  */
21
22 #include <stddef.h>     /* For offsetof.  */
23 #include <stdlib.h>     /* For abort().  */
24
25
26 /* We don't want to include the kernel header.  So duplicate the
27    information.  */
28
29 /* Structure passed on `modify_ldt' call.  */
30 struct modify_ldt_ldt_s
31 {
32   unsigned int entry_number;
33   unsigned long int base_addr;
34   unsigned int limit;
35   unsigned int seg_32bit:1;
36   unsigned int contents:2;
37   unsigned int read_exec_only:1;
38   unsigned int limit_in_pages:1;
39   unsigned int seg_not_present:1;
40   unsigned int useable:1;
41   unsigned int empty:25;
42 };
43
44 /* System call to set LDT entry.  */
45 extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
46
47
48 /* Return the thread descriptor for the current thread.
49
50    The contained asm must *not* be marked volatile since otherwise
51    assignments like
52         pthread_descr self = thread_self();
53    do not get optimized away.  */
54 #define THREAD_SELF \
55 ({                                                                            \
56   register pthread_descr __self;                                              \
57   __asm__ ("movl %%gs:%c1,%0" : "=r" (__self)                                 \
58            : "i" (offsetof (struct _pthread_descr_struct,                     \
59                             p_header.data.self)));                            \
60   __self;                                                                     \
61 })
62
63 /* Initialize the thread-unique value.  */
64 #define INIT_THREAD_SELF(descr, nr) \
65 {                                                                             \
66   struct modify_ldt_ldt_s ldt_entry =                                         \
67     { nr, (unsigned long int) descr, sizeof (*descr), 1, 0, 0, 0, 0, 1, 0 };  \
68   if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0)                  \
69     abort ();                                                                 \
70   __asm__ __volatile__ ("movw %w0, %%gs" : : "q" (nr * 8 + 7));               \
71 }
72
73 /* Free resources associated with thread descriptor.  */
74 #define FREE_THREAD(descr, nr) \
75 {                                                                             \
76   struct modify_ldt_ldt_s ldt_entry =                                         \
77     { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 };                                        \
78   __modify_ldt (1, &ldt_entry, sizeof (ldt_entry));                           \
79 }
80
81 /* Read member of the thread descriptor directly.  */
82 #define THREAD_GETMEM(descr, member) \
83 ({                                                                            \
84   __typeof__ (descr->member) __value;                                         \
85   if (sizeof (__value) == 1)                                                  \
86     __asm__ __volatile__ ("movb %%gs:%P2,%b0"                                 \
87                           : "=q" (__value)                                    \
88                           : "0" (0),                                          \
89                             "i" (offsetof (struct _pthread_descr_struct,      \
90                                            member)));                         \
91   else if (sizeof (__value) == 4)                                             \
92     __asm__ __volatile__ ("movl %%gs:%P1,%0"                                  \
93                           : "=r" (__value)                                    \
94                           : "i" (offsetof (struct _pthread_descr_struct,      \
95                                            member)));                         \
96   else                                                                        \
97     {                                                                         \
98       if (sizeof (__value) != 8)                                              \
99         /* There should not be any value with a size other than 1, 4 or 8.  */\
100         abort ();                                                             \
101                                                                               \
102       __asm__ __volatile__ ("movl %%gs:%P1,%%eax\n\t"                         \
103                             "movl %%gs:%P2,%%edx"                             \
104                             : "=A" (__value)                                  \
105                             : "i" (offsetof (struct _pthread_descr_struct,    \
106                                              member)),                        \
107                               "i" (offsetof (struct _pthread_descr_struct,    \
108                                              member) + 4));                   \
109     }                                                                         \
110   __value;                                                                    \
111 })
112
113 /* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
114 #define THREAD_GETMEM_NC(descr, member) \
115 ({                                                                            \
116   __typeof__ (descr->member) __value;                                         \
117   if (sizeof (__value) == 1)                                                  \
118     __asm__ __volatile__ ("movb %%gs:(%2),%b0"                                \
119                           : "=q" (__value)                                    \
120                           : "0" (0),                                          \
121                             "r" (offsetof (struct _pthread_descr_struct,      \
122                                            member)));                         \
123   else if (sizeof (__value) == 4)                                             \
124     __asm__ __volatile__ ("movl %%gs:(%1),%0"                                 \
125                           : "=r" (__value)                                    \
126                           : "r" (offsetof (struct _pthread_descr_struct,      \
127                                            member)));                         \
128   else                                                                        \
129     {                                                                         \
130       if (sizeof (__value) != 8)                                              \
131         /* There should not be any value with a size other than 1, 4 or 8.  */\
132         abort ();                                                             \
133                                                                               \
134       __asm__ __volatile__ ("movl %%gs:(%1),%%eax\n\t"                        \
135                             "movl %%gs:4(%1),%%edx"                           \
136                             : "=&A" (__value)                                 \
137                             : "r" (offsetof (struct _pthread_descr_struct,    \
138                                              member)));                       \
139     }                                                                         \
140   __value;                                                                    \
141 })
142
143 /* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
144 #define THREAD_SETMEM(descr, member, value) \
145 ({                                                                            \
146   __typeof__ (descr->member) __value = (value);                               \
147   if (sizeof (__value) == 1)                                                  \
148     __asm__ __volatile__ ("movb %0,%%gs:%P1" :                                \
149                           : "q" (__value),                                    \
150                             "i" (offsetof (struct _pthread_descr_struct,      \
151                                            member)));                         \
152   else if (sizeof (__value) == 4)                                             \
153     __asm__ __volatile__ ("movl %0,%%gs:%P1" :                                \
154                           : "r" (__value),                                    \
155                             "i" (offsetof (struct _pthread_descr_struct,      \
156                                            member)));                         \
157   else                                                                        \
158     {                                                                         \
159       if (sizeof (__value) != 8)                                              \
160         /* There should not be any value with a size other than 1, 4 or 8.  */\
161         abort ();                                                             \
162                                                                               \
163       __asm__ __volatile__ ("movl %%eax,%%gs:%P1\n\n"                         \
164                             "movl %%edx,%%gs:%P2" :                           \
165                             : "A" (__value),                                  \
166                               "i" (offsetof (struct _pthread_descr_struct,    \
167                                              member)),                        \
168                               "i" (offsetof (struct _pthread_descr_struct,    \
169                                              member) + 4));                   \
170     }                                                                         \
171 })
172
173 /* Set member of the thread descriptor directly.  */
174 #define THREAD_SETMEM_NC(descr, member, value) \
175 ({                                                                            \
176   __typeof__ (descr->member) __value = (value);                               \
177   if (sizeof (__value) == 1)                                                  \
178     __asm__ __volatile__ ("movb %0,%%gs:(%1)" :                               \
179                           : "q" (__value),                                    \
180                             "r" (offsetof (struct _pthread_descr_struct,      \
181                                            member)));                         \
182   else if (sizeof (__value) == 4)                                             \
183     __asm__ __volatile__ ("movl %0,%%gs:(%1)" :                               \
184                           : "r" (__value),                                    \
185                             "r" (offsetof (struct _pthread_descr_struct,      \
186                                            member)));                         \
187   else                                                                        \
188     {                                                                         \
189       if (sizeof (__value) != 8)                                              \
190         /* There should not be any value with a size other than 1, 4 or 8.  */\
191         abort ();                                                             \
192                                                                               \
193       __asm__ __volatile__ ("movl %%eax,%%gs:(%1)\n\t"                        \
194                             "movl %%edx,%%gs:4(%1)" :                         \
195                             : "A" (__value),                                  \
196                               "r" (offsetof (struct _pthread_descr_struct,    \
197                                              member)));                       \
198     }                                                                         \
199 })
200
201 /* We want the OS to assign stack addresses.  */
202 #define FLOATING_STACKS 1
203
204 /* Maximum size of the stack if the rlimit is unlimited.  */
205 #define ARCH_STACK_MAX_SIZE     8*1024*1024