2004-10-04 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/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 Free Software Foundation, Inc.
3    Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
4    This file is part of the GNU C Library.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #ifndef _LINUX_S390_SYSDEP_H
22 #define _LINUX_S390_SYSDEP_H
23
24 #include <sysdeps/s390/s390-64/sysdep.h>
25 #include <sysdeps/unix/sysdep.h>
26
27 /* For Linux we can use the system call table in the header file
28         /usr/include/asm/unistd.h
29    of the kernel.  But these symbols do not follow the SYS_* syntax
30    so we have to redefine the `SYS_ify' macro here.  */
31 /* In newer 2.1 kernels __NR_syscall is missing so we define it here.  */
32 #define __NR_syscall 0
33
34 /*
35  * Newer kernel versions redefined __NR_pread and __NR_pwrite to
36  * __NR_pread64 and __NR_pwrite64.
37  */
38 #ifndef __NR_pread
39 # define __NR_pread __NR_pread64
40 #endif
41 #ifndef __NR_pwrite
42 # define __NR_pwrite __NR_pwrite64
43 #endif
44
45 #undef SYS_ify
46 #define SYS_ify(syscall_name)   __NR_##syscall_name
47
48 #ifdef __ASSEMBLER__
49
50 /* Linux uses a negative return value to indicate syscall errors, unlike
51    most Unices, which use the condition codes' carry flag.
52
53    Since version 2.1 the return value of a system call might be negative
54    even if the call succeeded.  E.g., the `lseek' system call might return
55    a large offset.  Therefore we must not anymore test for < 0, but test
56    for a real error by making sure the value in gpr2 is a real error
57    number.  Linus said he will make sure the no syscall returns a value
58    in -1 .. -4095 as a valid result so we can savely test with -4095.  */
59
60 #undef PSEUDO
61 #define PSEUDO(name, syscall_name, args)                                      \
62   .text;                                                                      \
63   ENTRY (name)                                                                \
64     DO_CALL (syscall_name, args);                                             \
65     lghi %r4,-4095 ;                                                          \
66     clgr %r2,%r4 ;                                                            \
67     jgnl SYSCALL_ERROR_LABEL
68
69 #undef PSEUDO_END
70 #define PSEUDO_END(name)                                                      \
71   SYSCALL_ERROR_HANDLER;                                                      \
72   END (name)
73
74 #undef PSEUDO_NOERRNO
75 #define PSEUDO_NOERRNO(name, syscall_name, args)                              \
76   .text;                                                                      \
77   ENTRY (name)                                                                \
78     DO_CALL (syscall_name, args)
79
80 #undef PSEUDO_END_NOERRNO
81 #define PSEUDO_END_NOERRNO(name)                                              \
82   SYSCALL_ERROR_HANDLER;                                                      \
83   END (name)
84
85 #undef PSEUDO_ERRVAL
86 #define PSEUDO_ERRVAL(name, syscall_name, args)                               \
87   .text;                                                                      \
88   ENTRY (name)                                                                \
89     DO_CALL (syscall_name, args);                                             \
90     lcgr %r2,%r2
91
92 #undef PSEUDO_END_ERRVAL
93 #define PSEUDO_END_ERRVAL(name)                                               \
94   SYSCALL_ERROR_HANDLER;                                                      \
95   END (name)
96
97 #ifndef PIC
98 # define SYSCALL_ERROR_LABEL syscall_error
99 # define SYSCALL_ERROR_HANDLER
100 #else
101 # if RTLD_PRIVATE_ERRNO
102 #  define SYSCALL_ERROR_LABEL 0f
103 #  define SYSCALL_ERROR_HANDLER \
104 0:  larl  %r1,rtld_errno;                                                     \
105     lcr   %r2,%r2;                                                            \
106     st    %r2,0(%r1);                                                         \
107     lghi  %r2,-1;                                                             \
108     br    %r14
109 # elif defined _LIBC_REENTRANT
110 #  if USE___THREAD
111 #   ifndef NOT_IN_libc
112 #    define SYSCALL_ERROR_ERRNO __libc_errno
113 #   else
114 #    define SYSCALL_ERROR_ERRNO errno
115 #   endif
116 #   define SYSCALL_ERROR_LABEL 0f
117 #   define SYSCALL_ERROR_HANDLER \
118 0:  lcr   %r0,%r2;                                                            \
119     larl  %r1,SYSCALL_ERROR_ERRNO@indntpoff;                                  \
120     lg    %r1,0(%r1);                                                         \
121     ear   %r2,%a0;                                                            \
122     sllg  %r2,%r2,32;                                                         \
123     ear   %r2,%a1;                                                            \
124     st    %r0,0(%r1,%r2);                                                     \
125     lghi   %r2,-1;                                                            \
126     br    %r14
127 #  else
128 #   define SYSCALL_ERROR_LABEL syscall_error@plt
129 #   define SYSCALL_ERROR_HANDLER
130 #  endif
131 # else
132 #  define SYSCALL_ERROR_LABEL 0f
133 #  define SYSCALL_ERROR_HANDLER \
134 0:  larl  %r1,_GLOBAL_OFFSET_TABLE_;                                          \
135     lg    %r1,errno@GOT(%r1);                                                 \
136     lcr   %r2,%r2;                                                            \
137     st    %r2,0(%r1);                                                         \
138     lghi  %r2,-1;                                                             \
139     br    %r14
140 # endif /* _LIBC_REENTRANT */
141 #endif /* PIC */
142
143 /* Linux takes system call arguments in registers:
144
145         syscall number  1            call-clobbered
146         arg 1           2            call-clobbered
147         arg 2           3            call-clobbered
148         arg 3           4            call-clobbered
149         arg 4           5            call-clobbered
150         arg 5           6            call-saved
151
152    (Of course a function with say 3 arguments does not have entries for
153    arguments 4 and 5.)
154    S390 does not need to do ANY stack operations to get its parameters
155    right.
156  */
157
158 #define DO_CALL(syscall, args)                                                \
159   .if SYS_ify (syscall) < 256;                                                \
160     svc SYS_ify (syscall);                                                    \
161   .else;                                                                      \
162     lghi %r1,SYS_ify (syscall);                                               \
163     svc 0;                                                                    \
164   .endif
165
166 #define ret                                                                   \
167     br      14
168
169 #define ret_NOERRNO                                                           \
170     br      14
171
172 #define ret_ERRVAL                                                            \
173     br      14
174
175 #endif /* __ASSEMBLER__ */
176
177 #undef INLINE_SYSCALL
178 #define INLINE_SYSCALL(name, nr, args...)                                     \
179   ({                                                                          \
180     long _ret = INTERNAL_SYSCALL (name, , nr, args);                          \
181     if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_ret, ), 0))              \
182      {                                                                        \
183        __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, ));                         \
184        _ret = -1;                                                             \
185      }                                                                        \
186     _ret; })
187
188 #undef INTERNAL_SYSCALL_DECL
189 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
190
191 #undef INTERNAL_SYSCALL_DIRECT
192 #define INTERNAL_SYSCALL_DIRECT(name, err, nr, args...)                       \
193   ({                                                                          \
194     DECLARGS_##nr(args)                                                       \
195     register long _ret asm("2");                                              \
196     asm volatile (                                                            \
197     "svc    %b1\n\t"                                                          \
198     : "=d" (_ret)                                                             \
199     : "i" (__NR_##name) ASMFMT_##nr                                           \
200     : "memory" );                                                             \
201     _ret; })
202
203 #undef INTERNAL_SYSCALL_SVC0
204 #define INTERNAL_SYSCALL_SVC0(name, err, nr, args...)                         \
205   ({                                                                          \
206     DECLARGS_##nr(args)                                                       \
207     register unsigned long _nr asm("1") = (unsigned long)(__NR_##name);       \
208     register long _ret asm("2");                                              \
209     asm volatile (                                                            \
210     "svc    0\n\t"                                                            \
211     : "=d" (_ret)                                                             \
212     : "d" (_nr) ASMFMT_##nr                                                   \
213     : "memory" );                                                             \
214     _ret; })
215
216 #undef INTERNAL_SYSCALL_NCS
217 #define INTERNAL_SYSCALL_NCS(no, err, nr, args...)                            \
218   ({                                                                          \
219     DECLARGS_##nr(args)                                                       \
220     register unsigned long _nr asm("1") = (unsigned long)(no);                \
221     register long _ret asm("2");                                              \
222     asm volatile (                                                            \
223     "svc    0\n\t"                                                            \
224     : "=d" (_ret)                                                             \
225     : "d" (_nr) ASMFMT_##nr                                                   \
226     : "memory" );                                                             \
227     _ret; })
228
229 #undef INTERNAL_SYSCALL
230 #define INTERNAL_SYSCALL(name, err, nr, args...)                              \
231   (((__NR_##name) < 256) ?                                                    \
232     INTERNAL_SYSCALL_DIRECT(name, err, nr, args) :                            \
233     INTERNAL_SYSCALL_SVC0(name, err,nr, args))
234
235 #undef INTERNAL_SYSCALL_ERROR_P
236 #define INTERNAL_SYSCALL_ERROR_P(val, err)                                    \
237   ((unsigned long) (val) >= -4095UL)
238
239 #undef INTERNAL_SYSCALL_ERRNO
240 #define INTERNAL_SYSCALL_ERRNO(val, err)        (-(val))
241
242 #define DECLARGS_0()
243 #define DECLARGS_1(arg1) \
244         register unsigned long gpr2 asm ("2") = (unsigned long)(arg1);
245 #define DECLARGS_2(arg1, arg2) \
246         DECLARGS_1(arg1) \
247         register unsigned long gpr3 asm ("3") = (unsigned long)(arg2);
248 #define DECLARGS_3(arg1, arg2, arg3) \
249         DECLARGS_2(arg1, arg2) \
250         register unsigned long gpr4 asm ("4") = (unsigned long)(arg3);
251 #define DECLARGS_4(arg1, arg2, arg3, arg4) \
252         DECLARGS_3(arg1, arg2, arg3) \
253         register unsigned long gpr5 asm ("5") = (unsigned long)(arg4);
254 #define DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \
255         DECLARGS_4(arg1, arg2, arg3, arg4) \
256         register unsigned long gpr6 asm ("6") = (unsigned long)(arg5);
257
258 #define ASMFMT_0
259 #define ASMFMT_1 , "0" (gpr2)
260 #define ASMFMT_2 , "0" (gpr2), "d" (gpr3)
261 #define ASMFMT_3 , "0" (gpr2), "d" (gpr3), "d" (gpr4)
262 #define ASMFMT_4 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5)
263 #define ASMFMT_5 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6)
264
265 #endif /* _LINUX_S390_SYSDEP_H */