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. */
27 /* Define __set_errno() for INLINE_SYSCALL macro below. */
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
40 #define SYS_ify(syscall_name) __NR_##syscall_name
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. */
55 #define PSEUDO(name, syscall_name, args) \
58 DO_CALL (syscall_name, args); \
61 jnl SYSCALL_ERROR_LABEL
64 #define PSEUDO_END(name) \
65 SYSCALL_ERROR_HANDLER; \
69 #define PSEUDO_NOERRNO(name, syscall_name, args) \
72 DO_CALL (syscall_name, args)
74 #undef PSEUDO_END_NOERRNO
75 #define PSEUDO_END_NOERRNO(name) \
79 #define PSEUDO_ERRVAL(name, syscall_name, args) \
82 DO_CALL (syscall_name, args); \
85 #undef PSEUDO_END_ERRVAL
86 #define PSEUDO_END_ERRVAL(name) \
90 # define SYSCALL_ERROR_LABEL 0f
91 # define SYSCALL_ERROR_HANDLER \
93 1: l %r1,2f-1b(%r1); \
95 2: .long syscall_error
97 # if RTLD_PRIVATE_ERRNO
98 # define SYSCALL_ERROR_LABEL 0f
99 # define SYSCALL_ERROR_HANDLER \
101 1: al %r1,2f-1b(%r1); \
106 2: .long rtld_errno-1b
107 # elif defined _LIBC_REENTRANT
109 # define SYSCALL_ERROR_ERRNO __libc_errno
111 # define SYSCALL_ERROR_ERRNO errno
113 # define SYSCALL_ERROR_LABEL 0f
114 # define SYSCALL_ERROR_HANDLER \
117 1: al %r1,2f-1b(%r1); \
118 l %r1,SYSCALL_ERROR_ERRNO@gotntpoff(%r1); \
123 2: .long _GLOBAL_OFFSET_TABLE_-1b
125 # define SYSCALL_ERROR_LABEL 0f
126 # define SYSCALL_ERROR_HANDLER \
128 1: al %r1,2f-1b(%r1); \
129 l %r1,errno@GOT(%r1); \
134 2: .long _GLOBAL_OFFSET_TABLE_-1b
135 # endif /* _LIBC_REENTRANT */
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
148 (Of course a function with say 3 arguments does not have entries for
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) \
160 .if SYS_ify (syscall) < 256; \
161 svc SYS_ify (syscall); \
163 lhi %r1,SYS_ify (syscall); \
173 #define ret_NOERRNO \
179 #endif /* __ASSEMBLER__ */
181 #undef INLINE_SYSCALL
182 #define INLINE_SYSCALL(name, nr, args...) \
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, )); \
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...) \
198 DECLARGS_##nr(args) \
199 register int _ret asm("2"); \
203 : "i" (__NR_##name) ASMFMT_##nr \
207 #undef INTERNAL_SYSCALL_SVC0
208 #define INTERNAL_SYSCALL_SVC0(name, err, nr, args...) \
210 DECLARGS_##nr(args) \
211 register unsigned long _nr asm("1") = (unsigned long)(__NR_##name); \
212 register int _ret asm("2"); \
216 : "d" (_nr) ASMFMT_##nr \
220 #undef INTERNAL_SYSCALL_NCS
221 #define INTERNAL_SYSCALL_NCS(no, err, nr, args...) \
223 DECLARGS_##nr(args) \
224 register unsigned long _nr asm("1") = (unsigned long)(no); \
225 register int _ret asm("2"); \
229 : "d" (_nr) ASMFMT_##nr \
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))
247 #define DECLARGS_1(arg1) \
248 register unsigned long gpr2 asm ("2") = (unsigned long)(arg1);
249 #define DECLARGS_2(arg1, arg2) \
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);
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"
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 */
290 # define INLINE_VSYSCALL(name, nr, args...) \
296 if (__vdso_##name != NULL) \
298 _ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, , nr, ##args); \
299 if (!INTERNAL_SYSCALL_ERROR_P (_ret, )) \
301 if (INTERNAL_SYSCALL_ERRNO (_ret, ) != ENOSYS) \
305 _ret = INTERNAL_SYSCALL (name, , nr, ##args); \
306 if (INTERNAL_SYSCALL_ERROR_P (_ret, )) \
309 __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, )); \
316 # define INLINE_VSYSCALL(name, nr, args...) \
317 INLINE_SYSCALL (name, nr, ##args)
321 # define INTERNAL_VSYSCALL(name, err, nr, args...) \
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) \
333 _ret = INTERNAL_SYSCALL (name, err, nr, ##args); \
338 # define INTERNAL_VSYSCALL(name, err, nr, args...) \
339 INTERNAL_SYSCALL (name, err, nr, ##args)
342 /* This version is for internal uses when there is no desire
344 #define INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK(name, err, nr, args...) \
346 long int _ret = ENOSYS; \
348 if (__vdso_##name != NULL) \
349 _ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \
355 #define INTERNAL_VSYSCALL_NCS(fn, err, nr, args...) \
357 DECLARGS_##nr(args) \
358 register long _ret asm("2"); \
364 : "d" (fn) ASMFMT_##nr \
365 : "cc", "memory", "0", "1", "10" CLOBBER_##nr); \
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. */
373 /* For the time being just use stack_guard rather than a separate
375 # ifdef __ASSEMBLER__
376 # define PTR_MANGLE(reg, tmpreg) \
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)
383 # define PTR_MANGLE(var) \
384 (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
385 # define PTR_DEMANGLE(var) PTR_MANGLE (var)
389 #endif /* _LINUX_S390_SYSDEP_H */