]>
Commit | Line | Data |
---|---|---|
d4697bc9 | 1 | /* Copyright (C) 2000-2014 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 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://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> |
2c03b6db | 24 | #include <dl-sysdep.h> /* For RTLD_PRIVATE_ERRNO. */ |
00c2b3b9 | 25 | #include <tls.h> |
847b055c | 26 | |
0480c901 UD |
27 | /* Define __set_errno() for INLINE_SYSCALL macro below. */ |
28 | #ifndef __ASSEMBLER__ | |
29 | #include <errno.h> | |
30 | #endif | |
31 | ||
847b055c AJ |
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 | |
38 | ||
39 | #undef SYS_ify | |
40 | #define SYS_ify(syscall_name) __NR_##syscall_name | |
41 | ||
847b055c AJ |
42 | #ifdef __ASSEMBLER__ |
43 | ||
44 | /* Linux uses a negative return value to indicate syscall errors, unlike | |
45 | most Unices, which use the condition codes' carry flag. | |
46 | ||
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 | |
19df733e | 51 | number. Linus said he will make sure that no syscall returns a value |
847b055c AJ |
52 | in -1 .. -4095 as a valid result so we can savely test with -4095. */ |
53 | ||
847b055c AJ |
54 | #undef PSEUDO |
55 | #define PSEUDO(name, syscall_name, args) \ | |
56 | .text; \ | |
d063d164 | 57 | ENTRY (name) \ |
ffa8d2a0 | 58 | DO_CALL (syscall_name, args); \ |
847b055c | 59 | lhi %r4,-4095 ; \ |
d063d164 | 60 | clr %r2,%r4 ; \ |
e6ebd2e4 | 61 | jnl SYSCALL_ERROR_LABEL |
847b055c AJ |
62 | |
63 | #undef PSEUDO_END | |
64 | #define PSEUDO_END(name) \ | |
65 | SYSCALL_ERROR_HANDLER; \ | |
66 | END (name) | |
67 | ||
441ee043 | 68 | #undef PSEUDO_NOERRNO |
9eb88290 UD |
69 | #define PSEUDO_NOERRNO(name, syscall_name, args) \ |
70 | .text; \ | |
d063d164 | 71 | ENTRY (name) \ |
9eb88290 UD |
72 | DO_CALL (syscall_name, args) |
73 | ||
74 | #undef PSEUDO_END_NOERRNO | |
75 | #define PSEUDO_END_NOERRNO(name) \ | |
76 | END (name) | |
77 | ||
137ffcdc UD |
78 | #undef PSEUDO_ERRVAL |
79 | #define PSEUDO_ERRVAL(name, syscall_name, args) \ | |
80 | .text; \ | |
d063d164 | 81 | ENTRY (name) \ |
137ffcdc UD |
82 | DO_CALL (syscall_name, args); \ |
83 | lcr %r2,%r2 | |
84 | ||
85 | #undef PSEUDO_END_ERRVAL | |
86 | #define PSEUDO_END_ERRVAL(name) \ | |
87 | END (name) | |
88 | ||
847b055c | 89 | #ifndef PIC |
e6ebd2e4 UD |
90 | # define SYSCALL_ERROR_LABEL 0f |
91 | # define SYSCALL_ERROR_HANDLER \ | |
92 | 0: basr %r1,0; \ | |
93 | 1: l %r1,2f-1b(%r1); \ | |
94 | br %r1; \ | |
95 | 2: .long syscall_error | |
847b055c | 96 | #else |
e6ebd2e4 UD |
97 | # if RTLD_PRIVATE_ERRNO |
98 | # define SYSCALL_ERROR_LABEL 0f | |
99 | # define SYSCALL_ERROR_HANDLER \ | |
100 | 0: basr %r1,0; \ | |
101 | 1: al %r1,2f-1b(%r1); \ | |
102 | lcr %r2,%r2; \ | |
103 | st %r2,0(%r1); \ | |
104 | lhi %r2,-1; \ | |
105 | br %r14; \ | |
96c82b3f | 106 | 2: .long rtld_errno-1b |
e6ebd2e4 | 107 | # elif defined _LIBC_REENTRANT |
d063d164 UD |
108 | # ifndef NOT_IN_libc |
109 | # define SYSCALL_ERROR_ERRNO __libc_errno | |
110 | # else | |
111 | # define SYSCALL_ERROR_ERRNO errno | |
112 | # endif | |
113 | # define SYSCALL_ERROR_LABEL 0f | |
114 | # define SYSCALL_ERROR_HANDLER \ | |
e6ebd2e4 UD |
115 | 0: lcr %r0,%r2; \ |
116 | basr %r1,0; \ | |
117 | 1: al %r1,2f-1b(%r1); \ | |
00c2b3b9 UD |
118 | l %r1,SYSCALL_ERROR_ERRNO@gotntpoff(%r1); \ |
119 | ear %r2,%a0; \ | |
e6ebd2e4 UD |
120 | st %r0,0(%r1,%r2); \ |
121 | lhi %r2,-1; \ | |
122 | br %r14; \ | |
123 | 2: .long _GLOBAL_OFFSET_TABLE_-1b | |
e6ebd2e4 UD |
124 | # else |
125 | # define SYSCALL_ERROR_LABEL 0f | |
126 | # define SYSCALL_ERROR_HANDLER \ | |
127 | 0: basr %r1,0; \ | |
128 | 1: al %r1,2f-1b(%r1); \ | |
129 | l %r1,errno@GOT(%r1); \ | |
130 | lcr %r2,%r2; \ | |
131 | st %r2,0(%r1); \ | |
132 | lhi %r2,-1; \ | |
133 | br %r14; \ | |
134 | 2: .long _GLOBAL_OFFSET_TABLE_-1b | |
135 | # endif /* _LIBC_REENTRANT */ | |
847b055c | 136 | #endif /* PIC */ |
847b055c AJ |
137 | |
138 | /* Linux takes system call arguments in registers: | |
139 | ||
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 | |
145 | arg 5 6 call-saved | |
8d2e6a03 | 146 | arg 6 7 call-saved |
847b055c AJ |
147 | |
148 | (Of course a function with say 3 arguments does not have entries for | |
149 | arguments 4 and 5.) | |
8d2e6a03 RM |
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. | |
847b055c AJ |
153 | */ |
154 | ||
ffa8d2a0 | 155 | #define DO_CALL(syscall, args) \ |
8d2e6a03 RM |
156 | .if args > 5; \ |
157 | lr %r0,%r7; \ | |
158 | l %r7,96(%r15); \ | |
159 | .endif; \ | |
1739d268 UD |
160 | .if SYS_ify (syscall) < 256; \ |
161 | svc SYS_ify (syscall); \ | |
162 | .else; \ | |
163 | lhi %r1,SYS_ify (syscall); \ | |
164 | svc 0; \ | |
8d2e6a03 RM |
165 | .endif; \ |
166 | .if args > 5; \ | |
167 | lr %r7,%r0; \ | |
1739d268 | 168 | .endif |
847b055c AJ |
169 | |
170 | #define ret \ | |
171 | br 14 | |
172 | ||
9eb88290 UD |
173 | #define ret_NOERRNO \ |
174 | br 14 | |
175 | ||
137ffcdc UD |
176 | #define ret_ERRVAL \ |
177 | br 14 | |
178 | ||
847b055c AJ |
179 | #endif /* __ASSEMBLER__ */ |
180 | ||
181 | #undef INLINE_SYSCALL | |
369b849f RM |
182 | #define INLINE_SYSCALL(name, nr, args...) \ |
183 | ({ \ | |
6aca81bb | 184 | unsigned int _ret = INTERNAL_SYSCALL (name, , nr, args); \ |
a1ffb40e | 185 | if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (_ret, ))) \ |
369b849f | 186 | { \ |
6aca81bb UD |
187 | __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, )); \ |
188 | _ret = 0xffffffff; \ | |
369b849f | 189 | } \ |
6aca81bb UD |
190 | (int) _ret; }) |
191 | ||
192 | #undef INTERNAL_SYSCALL_DECL | |
193 | #define INTERNAL_SYSCALL_DECL(err) do { } while (0) | |
847b055c | 194 | |
1739d268 UD |
195 | #undef INTERNAL_SYSCALL_DIRECT |
196 | #define INTERNAL_SYSCALL_DIRECT(name, err, nr, args...) \ | |
369b849f RM |
197 | ({ \ |
198 | DECLARGS_##nr(args) \ | |
d5b6c817 | 199 | register int _ret asm("2"); \ |
369b849f | 200 | asm volatile ( \ |
369b849f | 201 | "svc %b1\n\t" \ |
6aca81bb | 202 | : "=d" (_ret) \ |
d5b6c817 UD |
203 | : "i" (__NR_##name) ASMFMT_##nr \ |
204 | : "memory" ); \ | |
205 | _ret; }) | |
369b849f | 206 | |
1739d268 UD |
207 | #undef INTERNAL_SYSCALL_SVC0 |
208 | #define INTERNAL_SYSCALL_SVC0(name, err, nr, args...) \ | |
209 | ({ \ | |
210 | DECLARGS_##nr(args) \ | |
211 | register unsigned long _nr asm("1") = (unsigned long)(__NR_##name); \ | |
212 | register int _ret asm("2"); \ | |
213 | asm volatile ( \ | |
214 | "svc 0\n\t" \ | |
215 | : "=d" (_ret) \ | |
bbb5e55c UD |
216 | : "d" (_nr) ASMFMT_##nr \ |
217 | : "memory" ); \ | |
218 | _ret; }) | |
219 | ||
220 | #undef INTERNAL_SYSCALL_NCS | |
221 | #define INTERNAL_SYSCALL_NCS(no, err, nr, args...) \ | |
222 | ({ \ | |
223 | DECLARGS_##nr(args) \ | |
224 | register unsigned long _nr asm("1") = (unsigned long)(no); \ | |
225 | register int _ret asm("2"); \ | |
226 | asm volatile ( \ | |
227 | "svc 0\n\t" \ | |
228 | : "=d" (_ret) \ | |
229 | : "d" (_nr) ASMFMT_##nr \ | |
1739d268 UD |
230 | : "memory" ); \ |
231 | _ret; }) | |
232 | ||
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)) | |
238 | ||
369b849f | 239 | #undef INTERNAL_SYSCALL_ERROR_P |
6aca81bb UD |
240 | #define INTERNAL_SYSCALL_ERROR_P(val, err) \ |
241 | ((unsigned int) (val) >= 0xfffff001u) | |
369b849f RM |
242 | |
243 | #undef INTERNAL_SYSCALL_ERRNO | |
6aca81bb | 244 | #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) |
369b849f | 245 | |
847b055c AJ |
246 | #define DECLARGS_0() |
247 | #define DECLARGS_1(arg1) \ | |
d5b6c817 | 248 | register unsigned long gpr2 asm ("2") = (unsigned long)(arg1); |
847b055c AJ |
249 | #define DECLARGS_2(arg1, arg2) \ |
250 | DECLARGS_1(arg1) \ | |
d5b6c817 | 251 | register unsigned long gpr3 asm ("3") = (unsigned long)(arg2); |
847b055c AJ |
252 | #define DECLARGS_3(arg1, arg2, arg3) \ |
253 | DECLARGS_2(arg1, arg2) \ | |
d5b6c817 | 254 | register unsigned long gpr4 asm ("4") = (unsigned long)(arg3); |
847b055c AJ |
255 | #define DECLARGS_4(arg1, arg2, arg3, arg4) \ |
256 | DECLARGS_3(arg1, arg2, arg3) \ | |
d5b6c817 | 257 | register unsigned long gpr5 asm ("5") = (unsigned long)(arg4); |
847b055c AJ |
258 | #define DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \ |
259 | DECLARGS_4(arg1, arg2, arg3, arg4) \ | |
d5b6c817 | 260 | register unsigned long gpr6 asm ("6") = (unsigned long)(arg5); |
8d2e6a03 RM |
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); | |
847b055c AJ |
264 | |
265 | #define ASMFMT_0 | |
d5b6c817 UD |
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) | |
8d2e6a03 | 271 | #define ASMFMT_6 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6), "d" (gpr7) |
847b055c | 272 | |
0480c901 UD |
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" | |
277 | #define CLOBBER_4 | |
278 | #define CLOBBER_5 | |
279 | #define CLOBBER_6 | |
280 | ||
281 | /* List of system calls which are supported as vsyscalls. */ | |
282 | #define HAVE_CLOCK_GETRES_VSYSCALL 1 | |
283 | #define HAVE_CLOCK_GETTIME_VSYSCALL 1 | |
284 | ||
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 */ | |
289 | #ifdef SHARED | |
290 | # define INLINE_VSYSCALL(name, nr, args...) \ | |
291 | ({ \ | |
292 | __label__ out; \ | |
293 | __label__ iserr; \ | |
294 | long int _ret; \ | |
295 | \ | |
296 | if (__vdso_##name != NULL) \ | |
297 | { \ | |
298 | _ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, , nr, ##args); \ | |
299 | if (!INTERNAL_SYSCALL_ERROR_P (_ret, )) \ | |
300 | goto out; \ | |
301 | if (INTERNAL_SYSCALL_ERRNO (_ret, ) != ENOSYS) \ | |
302 | goto iserr; \ | |
303 | } \ | |
304 | \ | |
305 | _ret = INTERNAL_SYSCALL (name, , nr, ##args); \ | |
306 | if (INTERNAL_SYSCALL_ERROR_P (_ret, )) \ | |
307 | { \ | |
308 | iserr: \ | |
d063d164 UD |
309 | __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, )); \ |
310 | _ret = -1L; \ | |
0480c901 UD |
311 | } \ |
312 | out: \ | |
313 | (int) _ret; \ | |
314 | }) | |
315 | #else | |
316 | # define INLINE_VSYSCALL(name, nr, args...) \ | |
317 | INLINE_SYSCALL (name, nr, ##args) | |
318 | #endif | |
319 | ||
320 | #ifdef SHARED | |
321 | # define INTERNAL_VSYSCALL(name, err, nr, args...) \ | |
322 | ({ \ | |
323 | __label__ out; \ | |
324 | long int _ret; \ | |
325 | \ | |
326 | if (__vdso_##name != NULL) \ | |
327 | { \ | |
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) \ | |
331 | goto out; \ | |
332 | } \ | |
333 | _ret = INTERNAL_SYSCALL (name, err, nr, ##args); \ | |
334 | out: \ | |
335 | _ret; \ | |
336 | }) | |
337 | #else | |
338 | # define INTERNAL_VSYSCALL(name, err, nr, args...) \ | |
339 | INTERNAL_SYSCALL (name, err, nr, ##args) | |
340 | #endif | |
341 | ||
342 | /* This version is for internal uses when there is no desire | |
343 | to set errno */ | |
344 | #define INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK(name, err, nr, args...) \ | |
345 | ({ \ | |
346 | long int _ret = ENOSYS; \ | |
347 | \ | |
348 | if (__vdso_##name != NULL) \ | |
349 | _ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \ | |
350 | else \ | |
351 | err = 1 << 28; \ | |
352 | _ret; \ | |
353 | }) | |
354 | ||
355 | #define INTERNAL_VSYSCALL_NCS(fn, err, nr, args...) \ | |
356 | ({ \ | |
357 | DECLARGS_##nr(args) \ | |
358 | register long _ret asm("2"); \ | |
359 | asm volatile ( \ | |
19df733e | 360 | "lr 10,14\n\t" \ |
0480c901 | 361 | "basr 14,%1\n\t" \ |
19df733e | 362 | "lr 14,10\n\t" \ |
0480c901 UD |
363 | : "=d" (_ret) \ |
364 | : "d" (fn) ASMFMT_##nr \ | |
19df733e | 365 | : "cc", "memory", "0", "1", "10" CLOBBER_##nr); \ |
0480c901 | 366 | _ret; }) |
00c2b3b9 UD |
367 | |
368 | /* Pointer mangling support. */ | |
a3848485 | 369 | #if IS_IN (rtld) |
00c2b3b9 UD |
370 | /* We cannot use the thread descriptor because in ld.so we use setjmp |
371 | earlier than the descriptor is initialized. */ | |
372 | #else | |
373 | /* For the time being just use stack_guard rather than a separate | |
374 | pointer_guard. */ | |
375 | # ifdef __ASSEMBLER__ | |
376 | # define PTR_MANGLE(reg, tmpreg) \ | |
377 | ear tmpreg,%a0; \ | |
378 | x reg,STACK_GUARD(tmpreg) | |
305bb37e UD |
379 | # define PTR_MANGLE2(reg, tmpreg) \ |
380 | x reg,STACK_GUARD(tmpreg) | |
00c2b3b9 UD |
381 | # define PTR_DEMANGLE(reg, tmpreg) PTR_MANGLE (reg, tmpreg) |
382 | # else | |
383 | # define PTR_MANGLE(var) \ | |
384 | (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ()) | |
385 | # define PTR_DEMANGLE(var) PTR_MANGLE (var) | |
386 | # endif | |
387 | #endif | |
388 | ||
847b055c | 389 | #endif /* _LINUX_S390_SYSDEP_H */ |