Changes and additions migrated from cvs.devel.redhat.com:/cvs/devel/glibc to fedora...
[glibc.git] / sysdeps / unix / sysv / linux / s390 / s390-32 / sysdep.h
blob55a2cd744333d919ce4d9a2f4b3f8b4923e0ad9c
1 /* Copyright (C) 2000,01,02,03,04 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #ifndef _LINUX_S390_SYSDEP_H
21 #define _LINUX_S390_SYSDEP_H
23 #include <sysdeps/s390/s390-32/sysdep.h>
24 #include <sysdeps/unix/sysdep.h>
26 /* For Linux we can use the system call table in the header file
27 /usr/include/asm/unistd.h
28 of the kernel. But these symbols do not follow the SYS_* syntax
29 so we have to redefine the `SYS_ify' macro here. */
30 /* in newer 2.1 kernels __NR_syscall is missing so we define it here */
31 #define __NR_syscall 0
33 #undef SYS_ify
34 #define SYS_ify(syscall_name) __NR_##syscall_name
36 #ifdef __ASSEMBLER__
38 /* Linux uses a negative return value to indicate syscall errors, unlike
39 most Unices, which use the condition codes' carry flag.
41 Since version 2.1 the return value of a system call might be negative
42 even if the call succeeded. E.g., the `lseek' system call might return
43 a large offset. Therefore we must not anymore test for < 0, but test
44 for a real error by making sure the value in gpr2 is a real error
45 number. Linus said he will make sure the no syscall returns a value
46 in -1 .. -4095 as a valid result so we can savely test with -4095. */
48 #undef PSEUDO
49 #define PSEUDO(name, syscall_name, args) \
50 .text; \
51 ENTRY (name) \
52 DO_CALL (syscall_name, args); \
53 lhi %r4,-4095 ; \
54 clr %r2,%r4 ; \
55 jnl SYSCALL_ERROR_LABEL
57 #undef PSEUDO_END
58 #define PSEUDO_END(name) \
59 SYSCALL_ERROR_HANDLER; \
60 END (name)
62 #undef PSEUDO_NOERRNO
63 #define PSEUDO_NOERRNO(name, syscall_name, args) \
64 .text; \
65 ENTRY (name) \
66 DO_CALL (syscall_name, args)
68 #undef PSEUDO_END_NOERRNO
69 #define PSEUDO_END_NOERRNO(name) \
70 END (name)
72 #undef PSEUDO_ERRVAL
73 #define PSEUDO_ERRVAL(name, syscall_name, args) \
74 .text; \
75 ENTRY (name) \
76 DO_CALL (syscall_name, args); \
77 lcr %r2,%r2
79 #undef PSEUDO_END_ERRVAL
80 #define PSEUDO_END_ERRVAL(name) \
81 END (name)
83 #ifndef PIC
84 # define SYSCALL_ERROR_LABEL 0f
85 # define SYSCALL_ERROR_HANDLER \
86 0: basr %r1,0; \
87 1: l %r1,2f-1b(%r1); \
88 br %r1; \
89 2: .long syscall_error
90 #else
91 # if RTLD_PRIVATE_ERRNO
92 # define SYSCALL_ERROR_LABEL 0f
93 # define SYSCALL_ERROR_HANDLER \
94 0: basr %r1,0; \
95 1: al %r1,2f-1b(%r1); \
96 lcr %r2,%r2; \
97 st %r2,0(%r1); \
98 lhi %r2,-1; \
99 br %r14; \
100 2: .long errno-1b
101 # elif defined _LIBC_REENTRANT
102 # if USE___THREAD
103 # ifndef NOT_IN_libc
104 # define SYSCALL_ERROR_ERRNO __libc_errno
105 # else
106 # define SYSCALL_ERROR_ERRNO errno
107 # endif
108 # define SYSCALL_ERROR_LABEL 0f
109 # define SYSCALL_ERROR_HANDLER \
110 0: lcr %r0,%r2; \
111 basr %r1,0; \
112 1: al %r1,2f-1b(%r1); \
113 l %r1,SYSCALL_ERROR_ERRNO@gotntpoff(%r1) \
114 ear %r2,%a0 \
115 st %r0,0(%r1,%r2); \
116 lhi %r2,-1; \
117 br %r14; \
118 2: .long _GLOBAL_OFFSET_TABLE_-1b
119 # else
120 # define SYSCALL_ERROR_LABEL 0f
121 # define SYSCALL_ERROR_HANDLER \
122 0: basr %r1,0; \
123 1: al %r1,2f-1b(%r1); \
124 br %r1; \
125 2: .long syscall_error@plt-1b
126 # endif
127 # else
128 # define SYSCALL_ERROR_LABEL 0f
129 # define SYSCALL_ERROR_HANDLER \
130 0: basr %r1,0; \
131 1: al %r1,2f-1b(%r1); \
132 l %r1,errno@GOT(%r1); \
133 lcr %r2,%r2; \
134 st %r2,0(%r1); \
135 lhi %r2,-1; \
136 br %r14; \
137 2: .long _GLOBAL_OFFSET_TABLE_-1b
138 # endif /* _LIBC_REENTRANT */
139 #endif /* PIC */
141 /* Linux takes system call arguments in registers:
143 syscall number 1 call-clobbered
144 arg 1 2 call-clobbered
145 arg 2 3 call-clobbered
146 arg 3 4 call-clobbered
147 arg 4 5 call-clobbered
148 arg 5 6 call-saved
150 (Of course a function with say 3 arguments does not have entries for
151 arguments 4 and 5.)
152 S390 does not need to do ANY stack operations to get its parameters
153 right.
156 #define DO_CALL(syscall, args) \
157 .if SYS_ify (syscall) < 256; \
158 svc SYS_ify (syscall); \
159 .else; \
160 lhi %r1,SYS_ify (syscall); \
161 svc 0; \
162 .endif
164 #define ret \
165 br 14
167 #define ret_NOERRNO \
168 br 14
170 #define ret_ERRVAL \
171 br 14
173 #endif /* __ASSEMBLER__ */
175 #undef INLINE_SYSCALL
176 #define INLINE_SYSCALL(name, nr, args...) \
177 ({ \
178 unsigned int _ret = INTERNAL_SYSCALL (name, , nr, args); \
179 if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_ret, ), 0)) \
181 __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, )); \
182 _ret = 0xffffffff; \
184 (int) _ret; })
186 #undef INTERNAL_SYSCALL_DECL
187 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
189 #undef INTERNAL_SYSCALL_DIRECT
190 #define INTERNAL_SYSCALL_DIRECT(name, err, nr, args...) \
191 ({ \
192 DECLARGS_##nr(args) \
193 register int _ret asm("2"); \
194 asm volatile ( \
195 "svc %b1\n\t" \
196 : "=d" (_ret) \
197 : "i" (__NR_##name) ASMFMT_##nr \
198 : "memory" ); \
199 _ret; })
201 #undef INTERNAL_SYSCALL_SVC0
202 #define INTERNAL_SYSCALL_SVC0(name, err, nr, args...) \
203 ({ \
204 DECLARGS_##nr(args) \
205 register unsigned long _nr asm("1") = (unsigned long)(__NR_##name); \
206 register int _ret asm("2"); \
207 asm volatile ( \
208 "svc 0\n\t" \
209 : "=d" (_ret) \
210 : "d" (_nr) ASMFMT_##nr \
211 : "memory" ); \
212 _ret; })
214 #undef INTERNAL_SYSCALL_NCS
215 #define INTERNAL_SYSCALL_NCS(no, err, nr, args...) \
216 ({ \
217 DECLARGS_##nr(args) \
218 register unsigned long _nr asm("1") = (unsigned long)(no); \
219 register int _ret asm("2"); \
220 asm volatile ( \
221 "svc 0\n\t" \
222 : "=d" (_ret) \
223 : "d" (_nr) ASMFMT_##nr \
224 : "memory" ); \
225 _ret; })
227 #undef INTERNAL_SYSCALL
228 #define INTERNAL_SYSCALL(name, err, nr, args...) \
229 (((__NR_##name) < 256) ? \
230 INTERNAL_SYSCALL_DIRECT(name, err, nr, args) : \
231 INTERNAL_SYSCALL_SVC0(name, err,nr, args))
233 #undef INTERNAL_SYSCALL_ERROR_P
234 #define INTERNAL_SYSCALL_ERROR_P(val, err) \
235 ((unsigned int) (val) >= 0xfffff001u)
237 #undef INTERNAL_SYSCALL_ERRNO
238 #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
240 #define DECLARGS_0()
241 #define DECLARGS_1(arg1) \
242 register unsigned long gpr2 asm ("2") = (unsigned long)(arg1);
243 #define DECLARGS_2(arg1, arg2) \
244 DECLARGS_1(arg1) \
245 register unsigned long gpr3 asm ("3") = (unsigned long)(arg2);
246 #define DECLARGS_3(arg1, arg2, arg3) \
247 DECLARGS_2(arg1, arg2) \
248 register unsigned long gpr4 asm ("4") = (unsigned long)(arg3);
249 #define DECLARGS_4(arg1, arg2, arg3, arg4) \
250 DECLARGS_3(arg1, arg2, arg3) \
251 register unsigned long gpr5 asm ("5") = (unsigned long)(arg4);
252 #define DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \
253 DECLARGS_4(arg1, arg2, arg3, arg4) \
254 register unsigned long gpr6 asm ("6") = (unsigned long)(arg5);
256 #define ASMFMT_0
257 #define ASMFMT_1 , "0" (gpr2)
258 #define ASMFMT_2 , "0" (gpr2), "d" (gpr3)
259 #define ASMFMT_3 , "0" (gpr2), "d" (gpr3), "d" (gpr4)
260 #define ASMFMT_4 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5)
261 #define ASMFMT_5 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6)
263 #endif /* _LINUX_S390_SYSDEP_H */