]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h
Remove support for !USE___THREAD
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / s390 / s390-64 / sysdep.h
1 /* Assembler macros for 64 bit S/390.
2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2011
3 Free Software Foundation, Inc.
4 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
5 This file is part of the GNU C Library.
6
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the 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 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with the GNU C Library; if not, write to the Free
19 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA. */
21
22 #ifndef _LINUX_S390_SYSDEP_H
23 #define _LINUX_S390_SYSDEP_H
24
25 #include <sysdeps/s390/s390-64/sysdep.h>
26 #include <sysdeps/unix/sysdep.h>
27 #include <dl-sysdep.h> /* For RTLD_PRIVATE_ERRNO. */
28 #include <tls.h>
29
30 /* Define __set_errno() for INLINE_SYSCALL macro below. */
31 #ifndef __ASSEMBLER__
32 #include <errno.h>
33 #endif
34
35 /* For Linux we can use the system call table in the header file
36 /usr/include/asm/unistd.h
37 of the kernel. But these symbols do not follow the SYS_* syntax
38 so we have to redefine the `SYS_ify' macro here. */
39 /* In newer 2.1 kernels __NR_syscall is missing so we define it here. */
40 #define __NR_syscall 0
41
42 /*
43 * Newer kernel versions redefined __NR_pread and __NR_pwrite to
44 * __NR_pread64 and __NR_pwrite64.
45 */
46 #ifndef __NR_pread
47 # define __NR_pread __NR_pread64
48 #endif
49 #ifndef __NR_pwrite
50 # define __NR_pwrite __NR_pwrite64
51 #endif
52
53 #undef SYS_ify
54 #define SYS_ify(syscall_name) __NR_##syscall_name
55
56 #ifdef __ASSEMBLER__
57
58 /* Linux uses a negative return value to indicate syscall errors, unlike
59 most Unices, which use the condition codes' carry flag.
60
61 Since version 2.1 the return value of a system call might be negative
62 even if the call succeeded. E.g., the `lseek' system call might return
63 a large offset. Therefore we must not anymore test for < 0, but test
64 for a real error by making sure the value in gpr2 is a real error
65 number. Linus said he will make sure that no syscall returns a value
66 in -1 .. -4095 as a valid result so we can savely test with -4095. */
67
68 #undef PSEUDO
69 #define PSEUDO(name, syscall_name, args) \
70 .text; \
71 ENTRY (name) \
72 DO_CALL (syscall_name, args); \
73 lghi %r4,-4095 ; \
74 clgr %r2,%r4 ; \
75 jgnl SYSCALL_ERROR_LABEL
76
77 #undef PSEUDO_END
78 #define PSEUDO_END(name) \
79 SYSCALL_ERROR_HANDLER; \
80 END (name)
81
82 #undef PSEUDO_NOERRNO
83 #define PSEUDO_NOERRNO(name, syscall_name, args) \
84 .text; \
85 ENTRY (name) \
86 DO_CALL (syscall_name, args)
87
88 #undef PSEUDO_END_NOERRNO
89 #define PSEUDO_END_NOERRNO(name) \
90 SYSCALL_ERROR_HANDLER; \
91 END (name)
92
93 #undef PSEUDO_ERRVAL
94 #define PSEUDO_ERRVAL(name, syscall_name, args) \
95 .text; \
96 ENTRY (name) \
97 DO_CALL (syscall_name, args); \
98 lcgr %r2,%r2
99
100 #undef PSEUDO_END_ERRVAL
101 #define PSEUDO_END_ERRVAL(name) \
102 SYSCALL_ERROR_HANDLER; \
103 END (name)
104
105 #ifndef PIC
106 # define SYSCALL_ERROR_LABEL syscall_error
107 # define SYSCALL_ERROR_HANDLER
108 #else
109 # if RTLD_PRIVATE_ERRNO
110 # define SYSCALL_ERROR_LABEL 0f
111 # define SYSCALL_ERROR_HANDLER \
112 0: larl %r1,rtld_errno; \
113 lcr %r2,%r2; \
114 st %r2,0(%r1); \
115 lghi %r2,-1; \
116 br %r14
117 # elif defined _LIBC_REENTRANT
118 # ifndef NOT_IN_libc
119 # define SYSCALL_ERROR_ERRNO __libc_errno
120 # else
121 # define SYSCALL_ERROR_ERRNO errno
122 # endif
123 # define SYSCALL_ERROR_LABEL 0f
124 # define SYSCALL_ERROR_HANDLER \
125 0: lcr %r0,%r2; \
126 larl %r1,SYSCALL_ERROR_ERRNO@indntpoff; \
127 lg %r1,0(%r1); \
128 ear %r2,%a0; \
129 sllg %r2,%r2,32; \
130 ear %r2,%a1; \
131 st %r0,0(%r1,%r2); \
132 lghi %r2,-1; \
133 br %r14
134 # else
135 # define SYSCALL_ERROR_LABEL 0f
136 # define SYSCALL_ERROR_HANDLER \
137 0: larl %r1,_GLOBAL_OFFSET_TABLE_; \
138 lg %r1,errno@GOT(%r1); \
139 lcr %r2,%r2; \
140 st %r2,0(%r1); \
141 lghi %r2,-1; \
142 br %r14
143 # endif /* _LIBC_REENTRANT */
144 #endif /* PIC */
145
146 /* Linux takes system call arguments in registers:
147
148 syscall number 1 call-clobbered
149 arg 1 2 call-clobbered
150 arg 2 3 call-clobbered
151 arg 3 4 call-clobbered
152 arg 4 5 call-clobbered
153 arg 5 6 call-saved
154 arg 6 7 call-saved
155
156 (Of course a function with say 3 arguments does not have entries for
157 arguments 4 and 5.)
158 For system calls with 6 parameters a stack operation is required
159 to load the 6th parameter to register 7. Call saved register 7 is
160 moved to register 0 and back to avoid an additional stack frame.
161 */
162
163 #define DO_CALL(syscall, args) \
164 .if args > 5; \
165 lgr %r0,%r7; \
166 lg %r7,160(%r15); \
167 .endif; \
168 .if SYS_ify (syscall) < 256; \
169 svc SYS_ify (syscall); \
170 .else; \
171 lghi %r1,SYS_ify (syscall); \
172 svc 0; \
173 .endif; \
174 .if args > 5; \
175 lgr %r7,%r0; \
176 .endif
177
178 #define ret \
179 br 14
180
181 #define ret_NOERRNO \
182 br 14
183
184 #define ret_ERRVAL \
185 br 14
186
187 #endif /* __ASSEMBLER__ */
188
189 #undef INLINE_SYSCALL
190 #define INLINE_SYSCALL(name, nr, args...) \
191 ({ \
192 long _ret = INTERNAL_SYSCALL (name, , nr, args); \
193 if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_ret, ), 0)) \
194 { \
195 __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, )); \
196 _ret = -1; \
197 } \
198 _ret; })
199
200 #undef INTERNAL_SYSCALL_DECL
201 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
202
203 #undef INTERNAL_SYSCALL_DIRECT
204 #define INTERNAL_SYSCALL_DIRECT(name, err, nr, args...) \
205 ({ \
206 DECLARGS_##nr(args) \
207 register long _ret asm("2"); \
208 asm volatile ( \
209 "svc %b1\n\t" \
210 : "=d" (_ret) \
211 : "i" (__NR_##name) ASMFMT_##nr \
212 : "memory" ); \
213 _ret; })
214
215 #undef INTERNAL_SYSCALL_SVC0
216 #define INTERNAL_SYSCALL_SVC0(name, err, nr, args...) \
217 ({ \
218 DECLARGS_##nr(args) \
219 register unsigned long _nr asm("1") = (unsigned long)(__NR_##name); \
220 register long _ret asm("2"); \
221 asm volatile ( \
222 "svc 0\n\t" \
223 : "=d" (_ret) \
224 : "d" (_nr) ASMFMT_##nr \
225 : "memory" ); \
226 _ret; })
227
228 #undef INTERNAL_SYSCALL_NCS
229 #define INTERNAL_SYSCALL_NCS(no, err, nr, args...) \
230 ({ \
231 DECLARGS_##nr(args) \
232 register unsigned long _nr asm("1") = (unsigned long)(no); \
233 register long _ret asm("2"); \
234 asm volatile ( \
235 "svc 0\n\t" \
236 : "=d" (_ret) \
237 : "d" (_nr) ASMFMT_##nr \
238 : "memory" ); \
239 _ret; })
240
241 #undef INTERNAL_SYSCALL
242 #define INTERNAL_SYSCALL(name, err, nr, args...) \
243 (((__NR_##name) < 256) ? \
244 INTERNAL_SYSCALL_DIRECT(name, err, nr, args) : \
245 INTERNAL_SYSCALL_SVC0(name, err,nr, args))
246
247 #undef INTERNAL_SYSCALL_ERROR_P
248 #define INTERNAL_SYSCALL_ERROR_P(val, err) \
249 ((unsigned long) (val) >= -4095UL)
250
251 #undef INTERNAL_SYSCALL_ERRNO
252 #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
253
254 #define DECLARGS_0()
255 #define DECLARGS_1(arg1) \
256 register unsigned long gpr2 asm ("2") = (unsigned long)(arg1);
257 #define DECLARGS_2(arg1, arg2) \
258 DECLARGS_1(arg1) \
259 register unsigned long gpr3 asm ("3") = (unsigned long)(arg2);
260 #define DECLARGS_3(arg1, arg2, arg3) \
261 DECLARGS_2(arg1, arg2) \
262 register unsigned long gpr4 asm ("4") = (unsigned long)(arg3);
263 #define DECLARGS_4(arg1, arg2, arg3, arg4) \
264 DECLARGS_3(arg1, arg2, arg3) \
265 register unsigned long gpr5 asm ("5") = (unsigned long)(arg4);
266 #define DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \
267 DECLARGS_4(arg1, arg2, arg3, arg4) \
268 register unsigned long gpr6 asm ("6") = (unsigned long)(arg5);
269 #define DECLARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \
270 DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \
271 register unsigned long gpr7 asm ("7") = (unsigned long)(arg6);
272
273 #define ASMFMT_0
274 #define ASMFMT_1 , "0" (gpr2)
275 #define ASMFMT_2 , "0" (gpr2), "d" (gpr3)
276 #define ASMFMT_3 , "0" (gpr2), "d" (gpr3), "d" (gpr4)
277 #define ASMFMT_4 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5)
278 #define ASMFMT_5 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6)
279 #define ASMFMT_6 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6), "d" (gpr7)
280
281 #define CLOBBER_0 , "3", "4", "5"
282 #define CLOBBER_1 , "3", "4", "5"
283 #define CLOBBER_2 , "4", "5"
284 #define CLOBBER_3 , "5"
285 #define CLOBBER_4
286 #define CLOBBER_5
287 #define CLOBBER_6
288
289 /* List of system calls which are supported as vsyscalls. */
290 #define HAVE_CLOCK_GETRES_VSYSCALL 1
291 #define HAVE_CLOCK_GETTIME_VSYSCALL 1
292
293 /* This version is for kernels that implement system calls that
294 behave like function calls as far as register saving.
295 It falls back to the syscall in the case that the vDSO doesn't
296 exist or fails for ENOSYS */
297 #ifdef SHARED
298 # define INLINE_VSYSCALL(name, nr, args...) \
299 ({ \
300 __label__ out; \
301 __label__ iserr; \
302 long int _ret; \
303 \
304 if (__vdso_##name != NULL) \
305 { \
306 _ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, , nr, ##args); \
307 if (!INTERNAL_SYSCALL_ERROR_P (_ret, )) \
308 goto out; \
309 if (INTERNAL_SYSCALL_ERRNO (_ret, ) != ENOSYS) \
310 goto iserr; \
311 } \
312 \
313 _ret = INTERNAL_SYSCALL (name, , nr, ##args); \
314 if (INTERNAL_SYSCALL_ERROR_P (_ret, )) \
315 { \
316 iserr: \
317 __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, )); \
318 _ret = -1L; \
319 } \
320 out: \
321 (int) _ret; \
322 })
323 #else
324 # define INLINE_VSYSCALL(name, nr, args...) \
325 INLINE_SYSCALL (name, nr, ##args)
326 #endif
327
328 #ifdef SHARED
329 # define INTERNAL_VSYSCALL(name, err, nr, args...) \
330 ({ \
331 __label__ out; \
332 long int _ret; \
333 \
334 if (__vdso_##name != NULL) \
335 { \
336 _ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \
337 if (!INTERNAL_SYSCALL_ERROR_P (_ret, err) \
338 || INTERNAL_SYSCALL_ERRNO (_ret, err) != ENOSYS) \
339 goto out; \
340 } \
341 _ret = INTERNAL_SYSCALL (name, err, nr, ##args); \
342 out: \
343 _ret; \
344 })
345 #else
346 # define INTERNAL_VSYSCALL(name, err, nr, args...) \
347 INTERNAL_SYSCALL (name, err, nr, ##args)
348 #endif
349
350 /* This version is for internal uses when there is no desire
351 to set errno */
352 #define INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK(name, err, nr, args...) \
353 ({ \
354 long int _ret = ENOSYS; \
355 \
356 if (__vdso_##name != NULL) \
357 _ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \
358 else \
359 err = 1 << 28; \
360 _ret; \
361 })
362
363 #define INTERNAL_VSYSCALL_NCS(fn, err, nr, args...) \
364 ({ \
365 DECLARGS_##nr(args) \
366 register long _ret asm("2"); \
367 asm volatile ( \
368 "lgr 10,14\n\t" \
369 "basr 14,%1\n\t" \
370 "lgr 14,10\n\t" \
371 : "=d" (_ret) \
372 : "a" (fn) ASMFMT_##nr \
373 : "cc", "memory", "0", "1", "10" CLOBBER_##nr); \
374 _ret; })
375
376 /* Pointer mangling support. */
377 #if defined NOT_IN_libc && defined IS_IN_rtld
378 /* We cannot use the thread descriptor because in ld.so we use setjmp
379 earlier than the descriptor is initialized. */
380 #else
381 /* For the time being just use stack_guard rather than a separate
382 pointer_guard. */
383 # ifdef __ASSEMBLER__
384 # define PTR_MANGLE(reg, tmpreg) \
385 ear tmpreg,%a0; \
386 sllg tmpreg,tmpreg,32; \
387 ear tmpreg,%a1; \
388 xg reg,STACK_GUARD(tmpreg)
389 # define PTR_MANGLE2(reg, tmpreg) \
390 xg reg,STACK_GUARD(tmpreg)
391 # define PTR_DEMANGLE(reg, tmpreg) PTR_MANGLE (reg, tmpreg)
392 # else
393 # define PTR_MANGLE(var) \
394 (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
395 # define PTR_DEMANGLE(var) PTR_MANGLE (var)
396 # endif
397 #endif
398
399 #endif /* _LINUX_S390_SYSDEP_H */