Back to index

glibc  2.9
useldt.h
Go to the documentation of this file.
00001 /* Special definitions for ix86 machine using segment register based
00002    thread descriptor.
00003    Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005    Contributed by Ulrich Drepper <drepper@cygnus.com>.
00006 
00007    The GNU C Library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public License as
00009    published by the Free Software Foundation; either version 2.1 of the
00010    License, or (at your option) any later version.
00011 
00012    The GNU C Library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with the GNU C Library; see the file COPYING.LIB.  If not,
00019    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020    Boston, MA 02111-1307, USA.     */
00021 
00022 #ifndef __ASSEMBLER__
00023 #include <stddef.h>  /* For offsetof.  */
00024 #include <stdlib.h>  /* For abort().       */
00025 #include <sysdep.h>
00026 
00027 
00028 /* We don't want to include the kernel header.   So duplicate the
00029    information.       */
00030 
00031 /* Structure passed on `modify_ldt' call.  */
00032 struct modify_ldt_ldt_s
00033 {
00034   unsigned int entry_number;
00035   unsigned long int base_addr;
00036   unsigned int limit;
00037   unsigned int seg_32bit:1;
00038   unsigned int contents:2;
00039   unsigned int read_exec_only:1;
00040   unsigned int limit_in_pages:1;
00041   unsigned int seg_not_present:1;
00042   unsigned int useable:1;
00043   unsigned int empty:25;
00044 };
00045 
00046 /* System call to set LDT entry.  */
00047 extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
00048 
00049 
00050 /* Return the thread descriptor for the current thread.
00051 
00052    The contained asm must *not* be marked volatile since otherwise
00053    assignments like
00054        pthread_descr self = thread_self();
00055    do not get optimized away.  */
00056 #define THREAD_SELF \
00057 ({                                                                   \
00058   register pthread_descr __self;                                     \
00059   __asm__ ("movl %%gs:%c1,%0" : "=r" (__self)                               \
00060           : "i" (offsetof (struct _pthread_descr_struct,                    \
00061                          p_header.data.self)));                      \
00062   __self;                                                            \
00063 })
00064 
00065 
00066 /* Initialize the thread-unique value.    Two possible ways to do it.  */
00067 
00068 #define DO_MODIFY_LDT(descr, nr)                                     \
00069 ({                                                                   \
00070   struct modify_ldt_ldt_s ldt_entry =                                       \
00071     { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */,          \
00072       1, 0, 0, 1, 0, 1, 0 };                                                \
00073   if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0)                \
00074     abort ();                                                        \
00075   asm ("movw %w0, %%gs" : : "q" (nr * 8 + 7));                              \
00076 })
00077 
00078 #ifdef __PIC__
00079 # define USETLS_EBX_ARG "r"
00080 # define USETLS_LOAD_EBX "xchgl %1, %%ebx\n\t"
00081 #else
00082 # define USETLS_EBX_ARG "b"
00083 # define USETLS_LOAD_EBX
00084 #endif
00085 
00086 /* When using the new set_thread_area call, we don't need to change %gs
00087    because we inherited the value set up in the main thread by TLS setup.
00088    We need to extract that value and set up the same segment in this
00089    thread.  */
00090 #if USE_TLS
00091 # define DO_SET_THREAD_AREA_REUSE(nr)     1
00092 #else
00093 /* Without TLS, we do the initialization of the main thread, where NR == 0.  */
00094 # define DO_SET_THREAD_AREA_REUSE(nr)     (!__builtin_constant_p (nr) || (nr))
00095 #endif
00096 #define DO_SET_THREAD_AREA(descr, nr) \
00097 ({                                                                   \
00098   int __gs;                                                          \
00099   if (DO_SET_THREAD_AREA_REUSE (nr))                                        \
00100     {                                                                \
00101       asm ("movw %%gs, %w0" : "=q" (__gs));                                 \
00102       struct modify_ldt_ldt_s ldt_entry =                            \
00103        { (__gs & 0xffff) >> 3,                                              \
00104          (unsigned long int) (descr), 0xfffff /* 4GB in pages */,           \
00105          1, 0, 0, 1, 0, 1, 0 };                                      \
00106                                                                      \
00107       int __result;                                                  \
00108       __asm (USETLS_LOAD_EBX                                                \
00109             "movl %2, %%eax\n\t"                                     \
00110             "int $0x80\n\t"                                          \
00111             USETLS_LOAD_EBX                                          \
00112             : "=&a" (__result)                                              \
00113             : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area),             \
00114               "m" (ldt_entry)                                               \
00115             : "memory");                                             \
00116       if (__result == 0)                                             \
00117        asm ("movw %w0, %%gs" :: "q" (__gs));                                \
00118       else                                                           \
00119        __gs = -1;                                                    \
00120     }                                                                \
00121   else                                                               \
00122     {                                                                \
00123       struct modify_ldt_ldt_s ldt_entry =                            \
00124        { -1,                                                         \
00125          (unsigned long int) (descr), 0xfffff /* 4GB in pages */,           \
00126          1, 0, 0, 1, 0, 1, 0 };                                      \
00127       int __result;                                                  \
00128       __asm (USETLS_LOAD_EBX                                                \
00129             "movl %2, %%eax\n\t"                                     \
00130             "int $0x80\n\t"                                          \
00131             USETLS_LOAD_EBX                                          \
00132             : "=&a" (__result)                                              \
00133             : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area),             \
00134               "m" (ldt_entry)                                               \
00135             : "memory");                                             \
00136       if (__result == 0)                                             \
00137        {                                                             \
00138          __gs = (ldt_entry.entry_number << 3) + 3;                          \
00139          asm ("movw %w0, %%gs" : : "q" (__gs));                      \
00140        }                                                             \
00141       else                                                           \
00142        __gs = -1;                                                    \
00143     }                                                                \
00144   __gs;                                                                     \
00145 })
00146 
00147 #if defined __ASSUME_SET_THREAD_AREA_SYSCALL
00148 # define INIT_THREAD_SELF(descr, nr)      DO_SET_THREAD_AREA (descr, nr)
00149 #elif defined __NR_set_thread_area
00150 # define INIT_THREAD_SELF(descr, nr)                                        \
00151 ({                                                                   \
00152   if (__builtin_expect (__have_no_set_thread_area, 0)                       \
00153       || (DO_SET_THREAD_AREA (descr, DO_SET_THREAD_AREA_REUSE (nr)) == -1     \
00154          && (__have_no_set_thread_area = 1)))                               \
00155     DO_MODIFY_LDT (descr, nr);                                              \
00156 })
00157 /* Defined in pspinlock.c.  */
00158 extern int __have_no_set_thread_area;
00159 #else
00160 # define INIT_THREAD_SELF(descr, nr)      DO_MODIFY_LDT (descr, nr)
00161 #endif
00162 
00163 /* Free resources associated with thread descriptor.  */
00164 #ifdef __ASSUME_SET_THREAD_AREA_SYSCALL
00165 #define FREE_THREAD(descr, nr) do { } while (0)
00166 #elif defined __NR_set_thread_area
00167 #define FREE_THREAD(descr, nr) \
00168 {                                                                    \
00169   int __gs;                                                          \
00170   __asm__ __volatile__ ("movw %%gs, %w0" : "=q" (__gs));                    \
00171   if (__builtin_expect (__gs & 4, 0))                                       \
00172     {                                                                \
00173       struct modify_ldt_ldt_s ldt_entry =                            \
00174        { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 };                            \
00175       __modify_ldt (1, &ldt_entry, sizeof (ldt_entry));                     \
00176     }                                                                \
00177 }
00178 #else
00179 #define FREE_THREAD(descr, nr) \
00180 {                                                                    \
00181   struct modify_ldt_ldt_s ldt_entry =                                       \
00182     { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 };                                      \
00183   __modify_ldt (1, &ldt_entry, sizeof (ldt_entry));                         \
00184 }
00185 #endif
00186 
00187 /* Read member of the thread descriptor directly.  */
00188 #define THREAD_GETMEM(descr, member) \
00189 ({                                                                   \
00190   __typeof__ (descr->member) __value;                                       \
00191   if (sizeof (__value) == 1)                                                \
00192     __asm__ __volatile__ ("movb %%gs:%P2,%b0"                               \
00193                        : "=q" (__value)                              \
00194                        : "0" (0),                                    \
00195                          "i" (offsetof (struct _pthread_descr_struct,      \
00196                                       member)));                     \
00197   else if (sizeof (__value) == 4)                                    \
00198     __asm__ __volatile__ ("movl %%gs:%P1,%0"                                \
00199                        : "=r" (__value)                              \
00200                        : "i" (offsetof (struct _pthread_descr_struct,      \
00201                                       member)));                     \
00202   else                                                               \
00203     {                                                                \
00204       if (sizeof (__value) != 8)                                     \
00205        /* There should not be any value with a size other than 1, 4 or 8.  */\
00206        abort ();                                                     \
00207                                                                      \
00208       __asm__ __volatile__ ("movl %%gs:%P1,%%eax\n\t"                       \
00209                          "movl %%gs:%P2,%%edx"                       \
00210                          : "=A" (__value)                            \
00211                          : "i" (offsetof (struct _pthread_descr_struct,    \
00212                                         member)),                           \
00213                            "i" (offsetof (struct _pthread_descr_struct,    \
00214                                         member) + 4));               \
00215     }                                                                \
00216   __value;                                                           \
00217 })
00218 
00219 /* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
00220 #define THREAD_GETMEM_NC(descr, member) \
00221 ({                                                                   \
00222   __typeof__ (descr->member) __value;                                       \
00223   if (sizeof (__value) == 1)                                                \
00224     __asm__ __volatile__ ("movb %%gs:(%2),%b0"                              \
00225                        : "=q" (__value)                              \
00226                        : "0" (0),                                    \
00227                          "r" (offsetof (struct _pthread_descr_struct,      \
00228                                       member)));                     \
00229   else if (sizeof (__value) == 4)                                    \
00230     __asm__ __volatile__ ("movl %%gs:(%1),%0"                               \
00231                        : "=r" (__value)                              \
00232                        : "r" (offsetof (struct _pthread_descr_struct,      \
00233                                       member)));                     \
00234   else                                                               \
00235     {                                                                \
00236       if (sizeof (__value) != 8)                                     \
00237        /* There should not be any value with a size other than 1, 4 or 8.  */\
00238        abort ();                                                     \
00239                                                                      \
00240       __asm__ __volatile__ ("movl %%gs:(%1),%%eax\n\t"                      \
00241                          "movl %%gs:4(%1),%%edx"                     \
00242                          : "=&A" (__value)                                  \
00243                          : "r" (offsetof (struct _pthread_descr_struct,    \
00244                                         member)));                          \
00245     }                                                                \
00246   __value;                                                           \
00247 })
00248 
00249 /* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
00250 #define THREAD_SETMEM(descr, member, value) \
00251 ({                                                                   \
00252   __typeof__ (descr->member) __value = (value);                             \
00253   if (sizeof (__value) == 1)                                                \
00254     __asm__ __volatile__ ("movb %0,%%gs:%P1" :                              \
00255                        : "q" (__value),                              \
00256                          "i" (offsetof (struct _pthread_descr_struct,      \
00257                                       member)));                     \
00258   else if (sizeof (__value) == 4)                                    \
00259     __asm__ __volatile__ ("movl %0,%%gs:%P1" :                              \
00260                        : "r" (__value),                              \
00261                          "i" (offsetof (struct _pthread_descr_struct,      \
00262                                       member)));                     \
00263   else                                                               \
00264     {                                                                \
00265       if (sizeof (__value) != 8)                                     \
00266        /* There should not be any value with a size other than 1, 4 or 8.  */\
00267        abort ();                                                     \
00268                                                                      \
00269       __asm__ __volatile__ ("movl %%eax,%%gs:%P1\n\n"                       \
00270                          "movl %%edx,%%gs:%P2" :                     \
00271                          : "A" (__value),                            \
00272                            "i" (offsetof (struct _pthread_descr_struct,    \
00273                                         member)),                           \
00274                            "i" (offsetof (struct _pthread_descr_struct,    \
00275                                         member) + 4));               \
00276     }                                                                \
00277 })
00278 
00279 /* Set member of the thread descriptor directly.  */
00280 #define THREAD_SETMEM_NC(descr, member, value) \
00281 ({                                                                   \
00282   __typeof__ (descr->member) __value = (value);                             \
00283   if (sizeof (__value) == 1)                                                \
00284     __asm__ __volatile__ ("movb %0,%%gs:(%1)" :                             \
00285                        : "q" (__value),                              \
00286                          "r" (offsetof (struct _pthread_descr_struct,      \
00287                                       member)));                     \
00288   else if (sizeof (__value) == 4)                                    \
00289     __asm__ __volatile__ ("movl %0,%%gs:(%1)" :                             \
00290                        : "r" (__value),                              \
00291                          "r" (offsetof (struct _pthread_descr_struct,      \
00292                                       member)));                     \
00293   else                                                               \
00294     {                                                                \
00295       if (sizeof (__value) != 8)                                     \
00296        /* There should not be any value with a size other than 1, 4 or 8.  */\
00297        abort ();                                                     \
00298                                                                      \
00299       __asm__ __volatile__ ("movl %%eax,%%gs:(%1)\n\t"                      \
00300                          "movl %%edx,%%gs:4(%1)" :                          \
00301                          : "A" (__value),                            \
00302                            "r" (offsetof (struct _pthread_descr_struct,    \
00303                                         member)));                          \
00304     }                                                                \
00305 })
00306 #endif
00307 
00308 #if __ASSUME_LDT_WORKS > 0
00309 /* We want the OS to assign stack addresses.  */
00310 #define FLOATING_STACKS     1
00311 
00312 /* Maximum size of the stack if the rlimit is unlimited.  */
00313 #define ARCH_STACK_MAX_SIZE 8*1024*1024
00314 #endif