]>
Commit | Line | Data |
---|---|---|
8321ef15 | 1 | /* Definitions for thread-local data handling. Hurd/i386 version. |
bfff8b1b | 2 | Copyright (C) 2003-2017 Free Software Foundation, Inc. |
8321ef15 RM |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
8321ef15 RM |
18 | |
19 | #ifndef _I386_TLS_H | |
20 | #define _I386_TLS_H | |
21 | ||
8321ef15 RM |
22 | |
23 | /* Some things really need not be machine-dependent. */ | |
83cd1420 | 24 | #include <sysdeps/mach/hurd/tls.h> |
8321ef15 | 25 | |
9f2a4fbc ST |
26 | |
27 | #ifndef __ASSEMBLER__ | |
aca1daef | 28 | # include <dl-dtv.h> |
9f2a4fbc ST |
29 | |
30 | /* Type of the TCB. */ | |
31 | typedef struct | |
32 | { | |
33 | void *tcb; /* Points to this structure. */ | |
34 | dtv_t *dtv; /* Vector of pointers to TLS data. */ | |
35 | thread_t self; /* This thread's control port. */ | |
3c799e91 ST |
36 | int multiple_threads; |
37 | uintptr_t sysinfo; | |
38 | uintptr_t stack_guard; | |
39 | uintptr_t pointer_guard; | |
40 | int gscope_flag; | |
41 | int private_futex; | |
42 | /* Reservation of some values for the TM ABI. */ | |
43 | void *__private_tm[4]; | |
44 | /* GCC split stack support. */ | |
45 | void *__private_ss; | |
9f2a4fbc ST |
46 | } tcbhead_t; |
47 | #endif | |
48 | ||
49 | ||
b0104b6f RM |
50 | /* The TCB can have any size and the memory following the address the |
51 | thread pointer points to is unspecified. Allocate the TCB there. */ | |
83cd1420 | 52 | #define TLS_TCB_AT_TP 1 |
498a2233 | 53 | #define TLS_DTV_AT_TP 0 |
b0104b6f | 54 | |
83cd1420 | 55 | #ifndef __ASSEMBLER__ |
b0104b6f | 56 | |
8321ef15 RM |
57 | /* Use i386-specific RPCs to arrange that %gs segment register prefix |
58 | addresses the TCB in each thread. */ | |
59 | # include <mach/i386/mach_i386.h> | |
60 | ||
b0104b6f | 61 | # ifndef HAVE_I386_SET_GDT |
09fb6292 | 62 | # define __i386_set_gdt(thr, sel, desc) ((void) (thr), (void) (sel), (void) (desc), MIG_BAD_ID) |
b0104b6f | 63 | # endif |
8321ef15 | 64 | |
b0104b6f RM |
65 | # include <errno.h> |
66 | # include <assert.h> | |
8321ef15 | 67 | |
83cd1420 | 68 | # define HURD_TLS_DESC_DECL(desc, tcb) \ |
3ba7b383 RM |
69 | struct descriptor desc = \ |
70 | { /* low word: */ \ | |
71 | 0xffff /* limit 0..15 */ \ | |
72 | | (((unsigned int) (tcb)) << 16) /* base 0..15 */ \ | |
73 | , /* high word: */ \ | |
74 | ((((unsigned int) (tcb)) >> 16) & 0xff) /* base 16..23 */ \ | |
75 | | ((0x12 | 0x60 | 0x80) << 8) /* access = ACC_DATA_W|ACC_PL_U|ACC_P */ \ | |
76 | | (0xf << 16) /* limit 16..19 */ \ | |
77 | | ((4 | 8) << 20) /* granularity = SZ_32|SZ_G */ \ | |
78 | | (((unsigned int) (tcb)) & 0xff000000) /* base 24..31 */ \ | |
79 | } | |
80 | ||
81 | ||
b0104b6f | 82 | static inline const char * __attribute__ ((unused)) |
774f9285 | 83 | _hurd_tls_init (tcbhead_t *tcb) |
8321ef15 | 84 | { |
3ba7b383 | 85 | HURD_TLS_DESC_DECL (desc, tcb); |
8321ef15 | 86 | |
774f9285 AS |
87 | /* This field is used by TLS accesses to get our "thread pointer" |
88 | from the TLS point of view. */ | |
89 | tcb->tcb = tcb; | |
90 | ||
91 | /* Cache our thread port. */ | |
92 | tcb->self = __mach_thread_self (); | |
93 | ||
94 | /* Get the first available selector. */ | |
95 | int sel = -1; | |
96 | error_t err = __i386_set_gdt (tcb->self, &sel, desc); | |
97 | if (err == MIG_BAD_ID) | |
8321ef15 | 98 | { |
774f9285 AS |
99 | /* Old kernel, use a per-thread LDT. */ |
100 | sel = 0x27; | |
101 | err = __i386_set_ldt (tcb->self, sel, &desc, 1); | |
102 | assert_perror (err); | |
103 | if (err) | |
104 | return "i386_set_ldt failed"; | |
8321ef15 | 105 | } |
774f9285 | 106 | else if (err) |
8321ef15 | 107 | { |
774f9285 AS |
108 | assert_perror (err); /* Separate from above with different line #. */ |
109 | return "i386_set_gdt failed"; | |
8321ef15 RM |
110 | } |
111 | ||
774f9285 AS |
112 | /* Now install the new selector. */ |
113 | asm volatile ("mov %w0, %%gs" :: "q" (sel)); | |
114 | ||
8321ef15 RM |
115 | return 0; |
116 | } | |
117 | ||
118 | /* Code to initially initialize the thread pointer. This might need | |
119 | special attention since 'errno' is not yet available and if the | |
120 | operation can cause a failure 'errno' must not be touched. */ | |
774f9285 AS |
121 | # define TLS_INIT_TP(descr) \ |
122 | _hurd_tls_init ((tcbhead_t *) (descr)) | |
05446770 RM |
123 | |
124 | /* Return the TCB address of the current thread. */ | |
83cd1420 | 125 | # define THREAD_SELF \ |
91b52f48 RM |
126 | ({ tcbhead_t *__tcb; \ |
127 | __asm__ ("movl %%gs:%c1,%0" : "=r" (__tcb) \ | |
128 | : "i" (offsetof (tcbhead_t, tcb))); \ | |
05446770 | 129 | __tcb;}) |
8321ef15 RM |
130 | |
131 | /* Install new dtv for current thread. */ | |
91b52f48 RM |
132 | # define INSTALL_NEW_DTV(dtvp) \ |
133 | ({ asm volatile ("movl %0,%%gs:%P1" \ | |
05446770 | 134 | : : "ir" (dtvp), "i" (offsetof (tcbhead_t, dtv))); }) |
8321ef15 RM |
135 | |
136 | /* Return the address of the dtv for the current thread. */ | |
83cd1420 | 137 | # define THREAD_DTV() \ |
b80f5da0 | 138 | ({ dtv_t *_dtv; \ |
91b52f48 | 139 | asm ("movl %%gs:%P1,%0" : "=q" (_dtv) : "i" (offsetof (tcbhead_t, dtv)));\ |
05446770 | 140 | _dtv; }) |
8321ef15 | 141 | |
83cd1420 | 142 | # include <mach/machine/thread_status.h> |
bcbfaf1d | 143 | |
3ba7b383 RM |
144 | /* Set up TLS in the new thread of a fork child, copying from our own. */ |
145 | static inline error_t __attribute__ ((unused)) | |
bcbfaf1d | 146 | _hurd_tls_fork (thread_t child, struct i386_thread_state *state) |
3ba7b383 RM |
147 | { |
148 | /* Fetch the selector set by _hurd_tls_init. */ | |
149 | int sel; | |
a935c3dc | 150 | asm ("mov %%gs, %w0" : "=q" (sel) : "0" (0)); |
3ba7b383 RM |
151 | if (sel == state->ds) /* _hurd_tls_init was never called. */ |
152 | return 0; | |
153 | ||
154 | tcbhead_t *const tcb = THREAD_SELF; | |
155 | HURD_TLS_DESC_DECL (desc, tcb); | |
156 | error_t err; | |
157 | ||
158 | if (__builtin_expect (sel, 0x50) & 4) /* LDT selector */ | |
159 | err = __i386_set_ldt (child, sel, &desc, 1); | |
160 | else | |
161 | err = __i386_set_gdt (child, &sel, desc); | |
162 | ||
163 | state->gs = sel; | |
164 | return err; | |
165 | } | |
166 | ||
83cd1420 | 167 | #endif /* !__ASSEMBLER__ */ |
8321ef15 RM |
168 | |
169 | #endif /* i386/tls.h */ |