55a2cd744333d919ce4d9a2f4b3f8b4923e0ad9c
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / s390 / s390-32 / sysdep.h
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.
4
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.
9
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.
14
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.  */
19
20 #ifndef _LINUX_S390_SYSDEP_H
21 #define _LINUX_S390_SYSDEP_H
22
23 #include <sysdeps/s390/s390-32/sysdep.h>
24 #include <sysdeps/unix/sysdep.h>
25
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
32
33 #undef SYS_ify
34 #define SYS_ify(syscall_name)   __NR_##syscall_name
35
36 #ifdef __ASSEMBLER__
37
38 /* Linux uses a negative return value to indicate syscall errors, unlike
39    most Unices, which use the condition codes' carry flag.
40
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.  */
47
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
56
57 #undef PSEUDO_END
58 #define PSEUDO_END(name)                                                      \
59   SYSCALL_ERROR_HANDLER;                                                      \
60   END (name)
61
62 #undef PSEUDO_NOERRNO
63 #define PSEUDO_NOERRNO(name, syscall_name, args)                              \
64   .text;                                                                      \
65   ENTRY (name)                                                                \
66     DO_CALL (syscall_name, args)
67
68 #undef PSEUDO_END_NOERRNO
69 #define PSEUDO_END_NOERRNO(name)                                              \
70   END (name)
71
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
78
79 #undef PSEUDO_END_ERRVAL
80 #define PSEUDO_END_ERRVAL(name)                                               \
81   END (name)
82
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 */
140
141 /* Linux takes system call arguments in registers:
142
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
149
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.
154  */
155
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
163
164 #define ret                                                                   \
165     br      14
166
167 #define ret_NOERRNO                                                           \
168     br      14
169
170 #define ret_ERRVAL                                                            \
171     br      14
172
173 #endif /* __ASSEMBLER__ */
174
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))              \
180      {                                                                        \
181        __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, ));                         \
182        _ret = 0xffffffff;                                                     \
183      }                                                                        \
184     (int) _ret; })
185
186 #undef INTERNAL_SYSCALL_DECL
187 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
188
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; })
200
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; })
213
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; })
226
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))
232
233 #undef INTERNAL_SYSCALL_ERROR_P
234 #define INTERNAL_SYSCALL_ERROR_P(val, err)                                    \
235   ((unsigned int) (val) >= 0xfffff001u)
236
237 #undef INTERNAL_SYSCALL_ERRNO
238 #define INTERNAL_SYSCALL_ERRNO(val, err)        (-(val))
239
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);
255
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)
262
263 #endif /* _LINUX_S390_SYSDEP_H */