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