]>
Commit | Line | Data |
---|---|---|
04277e02 | 1 | /* Copyright (C) 2000-2019 Free Software Foundation, Inc. |
847b055c AJ |
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 | |
41bdb6e2 AJ |
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. | |
847b055c AJ |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
847b055c | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
847b055c AJ |
18 | |
19 | #ifndef _LINUX_S390_SYSDEP_H | |
8cbdd648 | 20 | #define _LINUX_S390_SYSDEP_H |
847b055c | 21 | |
ffeac417 | 22 | #include <sysdeps/s390/s390-32/sysdep.h> |
847b055c | 23 | #include <sysdeps/unix/sysdep.h> |
b8386c28 | 24 | #include <sysdeps/unix/sysv/linux/s390/sysdep.h> |
fb1cf108 | 25 | #include <sysdeps/unix/sysv/linux/sysdep.h> |
2c03b6db | 26 | #include <dl-sysdep.h> /* For RTLD_PRIVATE_ERRNO. */ |
00c2b3b9 | 27 | #include <tls.h> |
847b055c | 28 | |
0480c901 UD |
29 | /* Define __set_errno() for INLINE_SYSCALL macro below. */ |
30 | #ifndef __ASSEMBLER__ | |
31 | #include <errno.h> | |
32 | #endif | |
33 | ||
847b055c AJ |
34 | /* For Linux we can use the system call table in the header file |
35 | /usr/include/asm/unistd.h | |
36 | of the kernel. But these symbols do not follow the SYS_* syntax | |
37 | so we have to redefine the `SYS_ify' macro here. */ | |
38 | /* in newer 2.1 kernels __NR_syscall is missing so we define it here */ | |
39 | #define __NR_syscall 0 | |
40 | ||
41 | #undef SYS_ify | |
42 | #define SYS_ify(syscall_name) __NR_##syscall_name | |
43 | ||
847b055c AJ |
44 | #ifdef __ASSEMBLER__ |
45 | ||
46 | /* Linux uses a negative return value to indicate syscall errors, unlike | |
47 | most Unices, which use the condition codes' carry flag. | |
48 | ||
49 | Since version 2.1 the return value of a system call might be negative | |
50 | even if the call succeeded. E.g., the `lseek' system call might return | |
51 | a large offset. Therefore we must not anymore test for < 0, but test | |
52 | for a real error by making sure the value in gpr2 is a real error | |
19df733e | 53 | number. Linus said he will make sure that no syscall returns a value |
847b055c AJ |
54 | in -1 .. -4095 as a valid result so we can savely test with -4095. */ |
55 | ||
847b055c AJ |
56 | #undef PSEUDO |
57 | #define PSEUDO(name, syscall_name, args) \ | |
58 | .text; \ | |
d063d164 | 59 | ENTRY (name) \ |
ffa8d2a0 | 60 | DO_CALL (syscall_name, args); \ |
847b055c | 61 | lhi %r4,-4095 ; \ |
d063d164 | 62 | clr %r2,%r4 ; \ |
e6ebd2e4 | 63 | jnl SYSCALL_ERROR_LABEL |
847b055c AJ |
64 | |
65 | #undef PSEUDO_END | |
66 | #define PSEUDO_END(name) \ | |
67 | SYSCALL_ERROR_HANDLER; \ | |
68 | END (name) | |
69 | ||
441ee043 | 70 | #undef PSEUDO_NOERRNO |
9eb88290 UD |
71 | #define PSEUDO_NOERRNO(name, syscall_name, args) \ |
72 | .text; \ | |
d063d164 | 73 | ENTRY (name) \ |
9eb88290 UD |
74 | DO_CALL (syscall_name, args) |
75 | ||
76 | #undef PSEUDO_END_NOERRNO | |
77 | #define PSEUDO_END_NOERRNO(name) \ | |
78 | END (name) | |
79 | ||
137ffcdc UD |
80 | #undef PSEUDO_ERRVAL |
81 | #define PSEUDO_ERRVAL(name, syscall_name, args) \ | |
82 | .text; \ | |
d063d164 | 83 | ENTRY (name) \ |
137ffcdc UD |
84 | DO_CALL (syscall_name, args); \ |
85 | lcr %r2,%r2 | |
86 | ||
87 | #undef PSEUDO_END_ERRVAL | |
88 | #define PSEUDO_END_ERRVAL(name) \ | |
89 | END (name) | |
90 | ||
847b055c | 91 | #ifndef PIC |
e6ebd2e4 UD |
92 | # define SYSCALL_ERROR_LABEL 0f |
93 | # define SYSCALL_ERROR_HANDLER \ | |
94 | 0: basr %r1,0; \ | |
95 | 1: l %r1,2f-1b(%r1); \ | |
96 | br %r1; \ | |
97 | 2: .long syscall_error | |
847b055c | 98 | #else |
e6ebd2e4 UD |
99 | # if RTLD_PRIVATE_ERRNO |
100 | # define SYSCALL_ERROR_LABEL 0f | |
101 | # define SYSCALL_ERROR_HANDLER \ | |
102 | 0: basr %r1,0; \ | |
103 | 1: al %r1,2f-1b(%r1); \ | |
104 | lcr %r2,%r2; \ | |
105 | st %r2,0(%r1); \ | |
106 | lhi %r2,-1; \ | |
107 | br %r14; \ | |
96c82b3f | 108 | 2: .long rtld_errno-1b |
e6ebd2e4 | 109 | # elif defined _LIBC_REENTRANT |
4f41c682 | 110 | # if IS_IN (libc) |
d063d164 UD |
111 | # define SYSCALL_ERROR_ERRNO __libc_errno |
112 | # else | |
113 | # define SYSCALL_ERROR_ERRNO errno | |
114 | # endif | |
115 | # define SYSCALL_ERROR_LABEL 0f | |
116 | # define SYSCALL_ERROR_HANDLER \ | |
e6ebd2e4 UD |
117 | 0: lcr %r0,%r2; \ |
118 | basr %r1,0; \ | |
119 | 1: al %r1,2f-1b(%r1); \ | |
00c2b3b9 UD |
120 | l %r1,SYSCALL_ERROR_ERRNO@gotntpoff(%r1); \ |
121 | ear %r2,%a0; \ | |
e6ebd2e4 UD |
122 | st %r0,0(%r1,%r2); \ |
123 | lhi %r2,-1; \ | |
124 | br %r14; \ | |
125 | 2: .long _GLOBAL_OFFSET_TABLE_-1b | |
e6ebd2e4 UD |
126 | # else |
127 | # define SYSCALL_ERROR_LABEL 0f | |
128 | # define SYSCALL_ERROR_HANDLER \ | |
129 | 0: basr %r1,0; \ | |
130 | 1: al %r1,2f-1b(%r1); \ | |
131 | l %r1,errno@GOT(%r1); \ | |
132 | lcr %r2,%r2; \ | |
133 | st %r2,0(%r1); \ | |
134 | lhi %r2,-1; \ | |
135 | br %r14; \ | |
136 | 2: .long _GLOBAL_OFFSET_TABLE_-1b | |
137 | # endif /* _LIBC_REENTRANT */ | |
847b055c | 138 | #endif /* PIC */ |
847b055c AJ |
139 | |
140 | /* Linux takes system call arguments in registers: | |
141 | ||
142 | syscall number 1 call-clobbered | |
143 | arg 1 2 call-clobbered | |
144 | arg 2 3 call-clobbered | |
145 | arg 3 4 call-clobbered | |
146 | arg 4 5 call-clobbered | |
147 | arg 5 6 call-saved | |
8d2e6a03 | 148 | arg 6 7 call-saved |
847b055c AJ |
149 | |
150 | (Of course a function with say 3 arguments does not have entries for | |
151 | arguments 4 and 5.) | |
8d2e6a03 RM |
152 | For system calls with 6 parameters a stack operation is required |
153 | to load the 6th parameter to register 7. Call saved register 7 is | |
154 | moved to register 0 and back to avoid an additional stack frame. | |
847b055c AJ |
155 | */ |
156 | ||
ffa8d2a0 | 157 | #define DO_CALL(syscall, args) \ |
8d2e6a03 RM |
158 | .if args > 5; \ |
159 | lr %r0,%r7; \ | |
160 | l %r7,96(%r15); \ | |
161 | .endif; \ | |
1739d268 UD |
162 | .if SYS_ify (syscall) < 256; \ |
163 | svc SYS_ify (syscall); \ | |
164 | .else; \ | |
165 | lhi %r1,SYS_ify (syscall); \ | |
166 | svc 0; \ | |
8d2e6a03 RM |
167 | .endif; \ |
168 | .if args > 5; \ | |
169 | lr %r7,%r0; \ | |
1739d268 | 170 | .endif |
847b055c AJ |
171 | |
172 | #define ret \ | |
173 | br 14 | |
174 | ||
9eb88290 UD |
175 | #define ret_NOERRNO \ |
176 | br 14 | |
177 | ||
137ffcdc UD |
178 | #define ret_ERRVAL \ |
179 | br 14 | |
180 | ||
847b055c AJ |
181 | #endif /* __ASSEMBLER__ */ |
182 | ||
183 | #undef INLINE_SYSCALL | |
369b849f RM |
184 | #define INLINE_SYSCALL(name, nr, args...) \ |
185 | ({ \ | |
6aca81bb | 186 | unsigned int _ret = INTERNAL_SYSCALL (name, , nr, args); \ |
a1ffb40e | 187 | if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (_ret, ))) \ |
369b849f | 188 | { \ |
6aca81bb UD |
189 | __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, )); \ |
190 | _ret = 0xffffffff; \ | |
369b849f | 191 | } \ |
6aca81bb UD |
192 | (int) _ret; }) |
193 | ||
194 | #undef INTERNAL_SYSCALL_DECL | |
195 | #define INTERNAL_SYSCALL_DECL(err) do { } while (0) | |
847b055c | 196 | |
1739d268 UD |
197 | #undef INTERNAL_SYSCALL_DIRECT |
198 | #define INTERNAL_SYSCALL_DIRECT(name, err, nr, args...) \ | |
369b849f RM |
199 | ({ \ |
200 | DECLARGS_##nr(args) \ | |
31cf3942 SL |
201 | register int _ret __asm__("2"); \ |
202 | __asm__ __volatile__ ( \ | |
203 | "svc %b1\n\t" \ | |
204 | : "=d" (_ret) \ | |
205 | : "i" (__NR_##name) ASMFMT_##nr \ | |
206 | : "memory" ); \ | |
d5b6c817 | 207 | _ret; }) |
369b849f | 208 | |
1739d268 UD |
209 | #undef INTERNAL_SYSCALL_SVC0 |
210 | #define INTERNAL_SYSCALL_SVC0(name, err, nr, args...) \ | |
211 | ({ \ | |
212 | DECLARGS_##nr(args) \ | |
31cf3942 SL |
213 | register unsigned long _nr __asm__("1") = (unsigned long)(__NR_##name); \ |
214 | register int _ret __asm__("2"); \ | |
215 | __asm__ __volatile__ ( \ | |
216 | "svc 0\n\t" \ | |
217 | : "=d" (_ret) \ | |
218 | : "d" (_nr) ASMFMT_##nr \ | |
219 | : "memory" ); \ | |
bbb5e55c UD |
220 | _ret; }) |
221 | ||
222 | #undef INTERNAL_SYSCALL_NCS | |
223 | #define INTERNAL_SYSCALL_NCS(no, err, nr, args...) \ | |
224 | ({ \ | |
225 | DECLARGS_##nr(args) \ | |
31cf3942 SL |
226 | register unsigned long _nr __asm__("1") = (unsigned long)(no); \ |
227 | register int _ret __asm__("2"); \ | |
228 | __asm__ __volatile__ ( \ | |
229 | "svc 0\n\t" \ | |
230 | : "=d" (_ret) \ | |
231 | : "d" (_nr) ASMFMT_##nr \ | |
232 | : "memory" ); \ | |
1739d268 UD |
233 | _ret; }) |
234 | ||
235 | #undef INTERNAL_SYSCALL | |
236 | #define INTERNAL_SYSCALL(name, err, nr, args...) \ | |
aa0e4663 JM |
237 | (((__NR_##name) < 256) \ |
238 | ? INTERNAL_SYSCALL_DIRECT(name, err, nr, args) \ | |
239 | : INTERNAL_SYSCALL_SVC0(name, err,nr, args)) | |
1739d268 | 240 | |
369b849f | 241 | #undef INTERNAL_SYSCALL_ERROR_P |
6aca81bb UD |
242 | #define INTERNAL_SYSCALL_ERROR_P(val, err) \ |
243 | ((unsigned int) (val) >= 0xfffff001u) | |
369b849f RM |
244 | |
245 | #undef INTERNAL_SYSCALL_ERRNO | |
6aca81bb | 246 | #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) |
369b849f | 247 | |
847b055c AJ |
248 | #define DECLARGS_0() |
249 | #define DECLARGS_1(arg1) \ | |
31cf3942 | 250 | register unsigned long gpr2 __asm__ ("2") = (unsigned long)(arg1); |
847b055c AJ |
251 | #define DECLARGS_2(arg1, arg2) \ |
252 | DECLARGS_1(arg1) \ | |
31cf3942 | 253 | register unsigned long gpr3 __asm__ ("3") = (unsigned long)(arg2); |
847b055c AJ |
254 | #define DECLARGS_3(arg1, arg2, arg3) \ |
255 | DECLARGS_2(arg1, arg2) \ | |
31cf3942 | 256 | register unsigned long gpr4 __asm__ ("4") = (unsigned long)(arg3); |
847b055c AJ |
257 | #define DECLARGS_4(arg1, arg2, arg3, arg4) \ |
258 | DECLARGS_3(arg1, arg2, arg3) \ | |
31cf3942 | 259 | register unsigned long gpr5 __asm__ ("5") = (unsigned long)(arg4); |
847b055c AJ |
260 | #define DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \ |
261 | DECLARGS_4(arg1, arg2, arg3, arg4) \ | |
31cf3942 | 262 | register unsigned long gpr6 __asm__ ("6") = (unsigned long)(arg5); |
8d2e6a03 RM |
263 | #define DECLARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ |
264 | DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \ | |
31cf3942 | 265 | register unsigned long gpr7 __asm__ ("7") = (unsigned long)(arg6); |
847b055c AJ |
266 | |
267 | #define ASMFMT_0 | |
d5b6c817 UD |
268 | #define ASMFMT_1 , "0" (gpr2) |
269 | #define ASMFMT_2 , "0" (gpr2), "d" (gpr3) | |
270 | #define ASMFMT_3 , "0" (gpr2), "d" (gpr3), "d" (gpr4) | |
271 | #define ASMFMT_4 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5) | |
272 | #define ASMFMT_5 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6) | |
8d2e6a03 | 273 | #define ASMFMT_6 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6), "d" (gpr7) |
847b055c | 274 | |
00c2b3b9 | 275 | /* Pointer mangling support. */ |
a3848485 | 276 | #if IS_IN (rtld) |
00c2b3b9 UD |
277 | /* We cannot use the thread descriptor because in ld.so we use setjmp |
278 | earlier than the descriptor is initialized. */ | |
279 | #else | |
280 | /* For the time being just use stack_guard rather than a separate | |
281 | pointer_guard. */ | |
282 | # ifdef __ASSEMBLER__ | |
283 | # define PTR_MANGLE(reg, tmpreg) \ | |
284 | ear tmpreg,%a0; \ | |
285 | x reg,STACK_GUARD(tmpreg) | |
305bb37e UD |
286 | # define PTR_MANGLE2(reg, tmpreg) \ |
287 | x reg,STACK_GUARD(tmpreg) | |
00c2b3b9 UD |
288 | # define PTR_DEMANGLE(reg, tmpreg) PTR_MANGLE (reg, tmpreg) |
289 | # else | |
290 | # define PTR_MANGLE(var) \ | |
291 | (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ()) | |
292 | # define PTR_DEMANGLE(var) PTR_MANGLE (var) | |
293 | # endif | |
294 | #endif | |
295 | ||
847b055c | 296 | #endif /* _LINUX_S390_SYSDEP_H */ |