]>
Commit | Line | Data |
---|---|---|
bfff8b1b | 1 | /* Copyright (C) 2005-2017 Free Software Foundation, Inc. |
da1ea0f0 CD |
2 | This file is part of the GNU C Library. |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
5 | modify it under the terms of the GNU Lesser General Public | |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
8 | ||
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | Lesser General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU Lesser General Public | |
ab84e3ff PE |
15 | License along with the GNU C Library. If not, see |
16 | <http://www.gnu.org/licenses/>. */ | |
da1ea0f0 CD |
17 | |
18 | #include <sysdep.h> | |
da1ea0f0 CD |
19 | #include <tls.h> |
20 | #ifndef __ASSEMBLER__ | |
21 | # include <nptl/pthreadP.h> | |
22 | #endif | |
23 | ||
4f41c682 | 24 | #if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt) |
da1ea0f0 CD |
25 | |
26 | # ifndef NO_ERROR | |
27 | # define NO_ERROR -0x1000 | |
28 | # endif | |
29 | ||
30 | /* The syscall cancellation mechanism requires userspace | |
31 | assistance, the following code does roughly this: | |
32 | ||
5abebba4 | 33 | do arguments (read arg5 and arg6 to registers) |
da1ea0f0 | 34 | setup frame |
5556231d | 35 | |
da1ea0f0 | 36 | check if there are threads, yes jump to pseudo_cancel |
5556231d | 37 | |
da1ea0f0 CD |
38 | unthreaded: |
39 | syscall | |
40 | check syscall return (jump to pre_end) | |
41 | set errno | |
42 | set return to -1 | |
43 | (jump to pre_end) | |
5556231d | 44 | |
da1ea0f0 CD |
45 | pseudo_cancel: |
46 | cenable | |
47 | syscall | |
48 | cdisable | |
49 | check syscall return (jump to pre_end) | |
50 | set errno | |
51 | set return to -1 | |
5556231d | 52 | |
da1ea0f0 CD |
53 | pre_end |
54 | restore stack | |
5556231d | 55 | |
da1ea0f0 | 56 | It is expected that 'ret' and 'END' macros will |
5556231d | 57 | append an 'undo arguments' and 'return' to the |
da1ea0f0 | 58 | this PSEUDO macro. */ |
5556231d | 59 | |
da1ea0f0 CD |
60 | # undef PSEUDO |
61 | # define PSEUDO(name, syscall_name, args) \ | |
8cb8321f CD |
62 | ENTRY (__##syscall_name##_nocancel) \ |
63 | DOARGS_##args ASM_LINE_SEP \ | |
64 | stwm TREG, 64(%sp) ASM_LINE_SEP \ | |
65 | .cfi_offset TREG, 0 ASM_LINE_SEP \ | |
66 | .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ | |
67 | stw %sp, -4(%sp) ASM_LINE_SEP \ | |
68 | .cfi_offset 30, -4 ASM_LINE_SEP \ | |
69 | stw %r19, -32(%sp) ASM_LINE_SEP \ | |
70 | .cfi_offset 19, -32 ASM_LINE_SEP \ | |
71 | /* Save r19 */ ASM_LINE_SEP \ | |
72 | SAVE_PIC(TREG) ASM_LINE_SEP \ | |
73 | /* Do syscall, delay loads # */ ASM_LINE_SEP \ | |
74 | ble 0x100(%sr2,%r0) ASM_LINE_SEP \ | |
75 | ldi SYS_ify (syscall_name), %r20 /* delay */ ASM_LINE_SEP \ | |
76 | ldi NO_ERROR,%r1 ASM_LINE_SEP \ | |
77 | cmpb,>>=,n %r1,%ret0,L(pre_nc_end) ASM_LINE_SEP \ | |
78 | /* Restore r19 from TREG */ ASM_LINE_SEP \ | |
79 | LOAD_PIC(TREG) /* delay */ ASM_LINE_SEP \ | |
80 | SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ | |
81 | /* Use TREG for temp storage */ ASM_LINE_SEP \ | |
82 | copy %ret0, TREG /* delay */ ASM_LINE_SEP \ | |
83 | /* OPTIMIZE: Don't reload r19 */ ASM_LINE_SEP \ | |
84 | /* do a -1*syscall_ret0 */ ASM_LINE_SEP \ | |
85 | sub %r0, TREG, TREG ASM_LINE_SEP \ | |
86 | /* Store into errno location */ ASM_LINE_SEP \ | |
87 | stw TREG, 0(%sr0,%ret0) ASM_LINE_SEP \ | |
88 | /* return -1 as error */ ASM_LINE_SEP \ | |
89 | ldi -1, %ret0 ASM_LINE_SEP \ | |
90 | L(pre_nc_end): ASM_LINE_SEP \ | |
91 | /* No need to LOAD_PIC */ ASM_LINE_SEP \ | |
92 | /* Undo frame */ ASM_LINE_SEP \ | |
93 | ldwm -64(%sp),TREG ASM_LINE_SEP \ | |
94 | .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ | |
95 | /* Restore rp before exit */ ASM_LINE_SEP \ | |
96 | ldw -20(%sp), %rp ASM_LINE_SEP \ | |
97 | .cfi_restore 2 ASM_LINE_SEP \ | |
98 | ret ASM_LINE_SEP \ | |
99 | END(__##syscall_name##_nocancel) ASM_LINE_SEP \ | |
100 | /**********************************************/ASM_LINE_SEP \ | |
da1ea0f0 CD |
101 | ENTRY (name) \ |
102 | DOARGS_##args ASM_LINE_SEP \ | |
0daa0500 | 103 | stwm TREG, 64(%sp) ASM_LINE_SEP \ |
8cb8321f | 104 | .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ |
0daa0500 | 105 | stw %sp, -4(%sp) ASM_LINE_SEP \ |
8cb8321f | 106 | .cfi_offset 30, -4 ASM_LINE_SEP \ |
0daa0500 | 107 | stw %r19, -32(%sp) ASM_LINE_SEP \ |
8cb8321f | 108 | .cfi_offset 19, -32 ASM_LINE_SEP \ |
da1ea0f0 CD |
109 | /* Done setting up frame, continue... */ ASM_LINE_SEP \ |
110 | SINGLE_THREAD_P ASM_LINE_SEP \ | |
111 | cmpib,<>,n 0,%ret0,L(pseudo_cancel) ASM_LINE_SEP \ | |
112 | L(unthreaded): ASM_LINE_SEP \ | |
113 | /* Save r19 */ ASM_LINE_SEP \ | |
114 | SAVE_PIC(TREG) ASM_LINE_SEP \ | |
115 | /* Do syscall, delay loads # */ ASM_LINE_SEP \ | |
116 | ble 0x100(%sr2,%r0) ASM_LINE_SEP \ | |
117 | ldi SYS_ify (syscall_name), %r20 /* delay */ ASM_LINE_SEP \ | |
118 | ldi NO_ERROR,%r1 ASM_LINE_SEP \ | |
119 | cmpb,>>=,n %r1,%ret0,L(pre_end) ASM_LINE_SEP \ | |
120 | /* Restore r19 from TREG */ ASM_LINE_SEP \ | |
121 | LOAD_PIC(TREG) /* delay */ ASM_LINE_SEP \ | |
122 | SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ | |
123 | /* Use TREG for temp storage */ ASM_LINE_SEP \ | |
124 | copy %ret0, TREG /* delay */ ASM_LINE_SEP \ | |
125 | /* OPTIMIZE: Don't reload r19 */ ASM_LINE_SEP \ | |
126 | /* do a -1*syscall_ret0 */ ASM_LINE_SEP \ | |
127 | sub %r0, TREG, TREG ASM_LINE_SEP \ | |
128 | /* Store into errno location */ ASM_LINE_SEP \ | |
129 | stw TREG, 0(%sr0,%ret0) ASM_LINE_SEP \ | |
130 | b L(pre_end) ASM_LINE_SEP \ | |
131 | /* return -1 as error */ ASM_LINE_SEP \ | |
0daa0500 | 132 | ldi -1, %ret0 /* delay */ ASM_LINE_SEP \ |
da1ea0f0 CD |
133 | L(pseudo_cancel): ASM_LINE_SEP \ |
134 | PUSHARGS_##args /* Save args */ ASM_LINE_SEP \ | |
135 | /* Save r19 into TREG */ ASM_LINE_SEP \ | |
136 | CENABLE /* FUNC CALL */ ASM_LINE_SEP \ | |
137 | SAVE_PIC(TREG) /* delay */ ASM_LINE_SEP \ | |
138 | /* restore syscall args */ ASM_LINE_SEP \ | |
139 | POPARGS_##args ASM_LINE_SEP \ | |
140 | /* save mask from cenable (use stub rp slot) */ ASM_LINE_SEP \ | |
141 | stw %ret0, -24(%sp) ASM_LINE_SEP \ | |
142 | /* ... SYSCALL ... */ ASM_LINE_SEP \ | |
143 | ble 0x100(%sr2,%r0) ASM_LINE_SEP \ | |
144 | ldi SYS_ify (syscall_name), %r20 /* delay */ ASM_LINE_SEP \ | |
145 | /* ............... */ ASM_LINE_SEP \ | |
146 | LOAD_PIC(TREG) ASM_LINE_SEP \ | |
147 | /* pass mask as arg0 to cdisable */ ASM_LINE_SEP \ | |
148 | ldw -24(%sp), %r26 ASM_LINE_SEP \ | |
149 | CDISABLE ASM_LINE_SEP \ | |
150 | stw %ret0, -24(%sp) /* delay */ ASM_LINE_SEP \ | |
151 | /* Restore syscall return */ ASM_LINE_SEP \ | |
152 | ldw -24(%sp), %ret0 ASM_LINE_SEP \ | |
153 | /* compare error */ ASM_LINE_SEP \ | |
154 | ldi NO_ERROR,%r1 ASM_LINE_SEP \ | |
155 | /* branch if no error */ ASM_LINE_SEP \ | |
156 | cmpb,>>=,n %r1,%ret0,L(pre_end) ASM_LINE_SEP \ | |
157 | LOAD_PIC(TREG) /* cond. nullify */ ASM_LINE_SEP \ | |
158 | copy %ret0, TREG /* save syscall return */ ASM_LINE_SEP \ | |
159 | SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ | |
160 | /* make syscall res value positive */ ASM_LINE_SEP \ | |
161 | sub %r0, TREG, TREG /* delay */ ASM_LINE_SEP \ | |
162 | /* No need to LOAD_PIC */ ASM_LINE_SEP \ | |
163 | /* store into errno location */ ASM_LINE_SEP \ | |
164 | stw TREG, 0(%sr0,%ret0) ASM_LINE_SEP \ | |
165 | /* return -1 */ ASM_LINE_SEP \ | |
0daa0500 | 166 | ldi -1, %ret0 ASM_LINE_SEP \ |
da1ea0f0 | 167 | L(pre_end): ASM_LINE_SEP \ |
0daa0500 | 168 | /* No need to LOAD_PIC */ ASM_LINE_SEP \ |
da1ea0f0 CD |
169 | /* Undo frame */ ASM_LINE_SEP \ |
170 | ldwm -64(%sp),TREG ASM_LINE_SEP \ | |
8cb8321f | 171 | .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ |
0daa0500 | 172 | /* Restore rp before exit */ ASM_LINE_SEP \ |
8cb8321f CD |
173 | ldw -20(%sp), %rp ASM_LINE_SEP \ |
174 | .cfi_restore 2 ASM_LINE_SEP | |
da1ea0f0 CD |
175 | |
176 | /* Save arguments into our frame */ | |
177 | # define PUSHARGS_0 /* nothing to do */ | |
8cb8321f CD |
178 | # define PUSHARGS_1 PUSHARGS_0 stw %r26, -36(%sr0,%sp) ASM_LINE_SEP \ |
179 | .cfi_offset 26, -36 ASM_LINE_SEP | |
180 | # define PUSHARGS_2 PUSHARGS_1 stw %r25, -40(%sr0,%sp) ASM_LINE_SEP \ | |
181 | .cfi_offset 25, -40 ASM_LINE_SEP | |
182 | # define PUSHARGS_3 PUSHARGS_2 stw %r24, -44(%sr0,%sp) ASM_LINE_SEP \ | |
183 | .cfi_offset 24, -44 ASM_LINE_SEP | |
184 | # define PUSHARGS_4 PUSHARGS_3 stw %r23, -48(%sr0,%sp) ASM_LINE_SEP \ | |
185 | .cfi_offset 23, -48 ASM_LINE_SEP | |
186 | # define PUSHARGS_5 PUSHARGS_4 stw %r22, -52(%sr0,%sp) ASM_LINE_SEP \ | |
187 | .cfi_offset 22, -52 ASM_LINE_SEP | |
188 | # define PUSHARGS_6 PUSHARGS_5 stw %r21, -56(%sr0,%sp) ASM_LINE_SEP \ | |
189 | .cfi_offset 21, -56 ASM_LINE_SEP | |
da1ea0f0 CD |
190 | |
191 | /* Bring them back from the stack */ | |
192 | # define POPARGS_0 /* nothing to do */ | |
8cb8321f CD |
193 | # define POPARGS_1 POPARGS_0 ldw -36(%sr0,%sp), %r26 ASM_LINE_SEP \ |
194 | .cfi_restore 26 ASM_LINE_SEP | |
195 | # define POPARGS_2 POPARGS_1 ldw -40(%sr0,%sp), %r25 ASM_LINE_SEP \ | |
196 | .cfi_restore 25 ASM_LINE_SEP | |
197 | # define POPARGS_3 POPARGS_2 ldw -44(%sr0,%sp), %r24 ASM_LINE_SEP \ | |
198 | .cfi_restore 24 ASM_LINE_SEP | |
199 | # define POPARGS_4 POPARGS_3 ldw -48(%sr0,%sp), %r23 ASM_LINE_SEP \ | |
200 | .cfi_restore 23 ASM_LINE_SEP | |
201 | # define POPARGS_5 POPARGS_4 ldw -52(%sr0,%sp), %r22 ASM_LINE_SEP \ | |
202 | .cfi_restore 22 ASM_LINE_SEP | |
203 | # define POPARGS_6 POPARGS_5 ldw -56(%sr0,%sp), %r21 ASM_LINE_SEP \ | |
204 | .cfi_restore 21 ASM_LINE_SEP | |
da1ea0f0 | 205 | |
ce9f10f7 | 206 | # if IS_IN (libpthread) |
da1ea0f0 CD |
207 | # ifdef PIC |
208 | # define CENABLE .import __pthread_enable_asynccancel,code ASM_LINE_SEP \ | |
209 | bl __pthread_enable_asynccancel,%r2 ASM_LINE_SEP | |
210 | # define CDISABLE .import __pthread_disable_asynccancel,code ASM_LINE_SEP \ | |
211 | bl __pthread_disable_asynccancel,%r2 ASM_LINE_SEP | |
212 | # else | |
213 | # define CENABLE .import __pthread_enable_asynccancel,code ASM_LINE_SEP \ | |
214 | bl __pthread_enable_asynccancel,%r2 ASM_LINE_SEP | |
215 | # define CDISABLE .import __pthread_disable_asynccancel,code ASM_LINE_SEP \ | |
216 | bl __pthread_disable_asynccancel,%r2 ASM_LINE_SEP | |
217 | # endif | |
4f41c682 | 218 | # elif IS_IN (libc) |
da1ea0f0 CD |
219 | # ifdef PIC |
220 | # define CENABLE .import __libc_enable_asynccancel,code ASM_LINE_SEP \ | |
221 | bl __libc_enable_asynccancel,%r2 ASM_LINE_SEP | |
222 | # define CDISABLE .import __libc_disable_asynccancel,code ASM_LINE_SEP \ | |
223 | bl __libc_disable_asynccancel,%r2 ASM_LINE_SEP | |
224 | # else | |
225 | # define CENABLE .import __libc_enable_asynccancel,code ASM_LINE_SEP \ | |
226 | bl __libc_enable_asynccancel,%r2 ASM_LINE_SEP | |
227 | # define CDISABLE .import __libc_disable_asynccancel,code ASM_LINE_SEP \ | |
228 | bl __libc_disable_asynccancel,%r2 ASM_LINE_SEP | |
229 | # endif | |
016afc75 | 230 | # elif IS_IN (librt) |
da1ea0f0 CD |
231 | # ifdef PIC |
232 | # define CENABLE .import __librt_enable_asynccancel,code ASM_LINE_SEP \ | |
233 | bl __librt_enable_asynccancel,%r2 ASM_LINE_SEP | |
234 | # define CDISABLE .import __librt_disable_asynccancel,code ASM_LINE_SEP \ | |
235 | bl __librt_disable_asynccancel,%r2 ASM_LINE_SEP | |
236 | # else | |
237 | # define CENABLE .import __librt_enable_asynccancel,code ASM_LINE_SEP \ | |
238 | bl __librt_enable_asynccancel,%r2 ASM_LINE_SEP | |
239 | # define CDISABLE .import __librt_disable_asynccancel,code ASM_LINE_SEP \ | |
240 | bl __librt_disable_asynccancel,%r2 ASM_LINE_SEP | |
241 | # endif | |
cd153083 CD |
242 | # else |
243 | # error Unsupported library | |
da1ea0f0 CD |
244 | # endif |
245 | ||
ce9f10f7 | 246 | # if IS_IN (libpthread) |
da1ea0f0 | 247 | # define __local_multiple_threads __pthread_multiple_threads |
4f41c682 | 248 | # elif IS_IN (libc) |
da1ea0f0 | 249 | # define __local_multiple_threads __libc_multiple_threads |
016afc75 | 250 | # elif IS_IN (librt) |
da1ea0f0 | 251 | # define __local_multiple_threads __librt_multiple_threads |
cd153083 CD |
252 | # else |
253 | # error Unsupported library | |
da1ea0f0 CD |
254 | # endif |
255 | ||
256 | # ifndef __ASSEMBLER__ | |
257 | # define SINGLE_THREAD_P \ | |
258 | __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ | |
259 | header.multiple_threads) == 0, 1) | |
260 | # else | |
261 | /* Read the value of header.multiple_threads from the thread pointer */ | |
5abebba4 | 262 | # define SINGLE_THREAD_P \ |
da1ea0f0 CD |
263 | mfctl %cr27, %ret0 ASM_LINE_SEP \ |
264 | ldw MULTIPLE_THREADS_THREAD_OFFSET(%sr0,%ret0),%ret0 ASM_LINE_SEP | |
265 | # endif | |
266 | #elif !defined __ASSEMBLER__ | |
267 | ||
268 | /* This code should never be used but we define it anyhow. */ | |
269 | # define SINGLE_THREAD_P (1) | |
270 | # define NO_CANCELLATION 1 | |
271 | ||
272 | #endif | |
4f41c682 | 273 | /* IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt) */ |
d396ccd5 CD |
274 | |
275 | #ifndef __ASSEMBLER__ | |
276 | # define RTLD_SINGLE_THREAD_P \ | |
277 | __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ | |
278 | header.multiple_threads) == 0, 1) | |
279 | #endif |