]>
Commit | Line | Data |
---|---|---|
d063d164 | 1 | /* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2011 |
00c2b3b9 | 2 | Free Software Foundation, Inc. |
847b055c AJ |
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 | |
41bdb6e2 AJ |
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. | |
847b055c AJ |
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 | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
847b055c | 15 | |
41bdb6e2 | 16 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
17 | License along with the GNU C Library; if not, see |
18 | <http://www.gnu.org/licenses/>. */ | |
847b055c AJ |
19 | |
20 | #ifndef _LINUX_S390_SYSDEP_H | |
8cbdd648 | 21 | #define _LINUX_S390_SYSDEP_H |
847b055c | 22 | |
ffeac417 | 23 | #include <sysdeps/s390/s390-32/sysdep.h> |
847b055c | 24 | #include <sysdeps/unix/sysdep.h> |
2c03b6db | 25 | #include <dl-sysdep.h> /* For RTLD_PRIVATE_ERRNO. */ |
00c2b3b9 | 26 | #include <tls.h> |
847b055c | 27 | |
0480c901 UD |
28 | /* Define __set_errno() for INLINE_SYSCALL macro below. */ |
29 | #ifndef __ASSEMBLER__ | |
30 | #include <errno.h> | |
31 | #endif | |
32 | ||
847b055c AJ |
33 | /* For Linux we can use the system call table in the header file |
34 | /usr/include/asm/unistd.h | |
35 | of the kernel. But these symbols do not follow the SYS_* syntax | |
36 | so we have to redefine the `SYS_ify' macro here. */ | |
37 | /* in newer 2.1 kernels __NR_syscall is missing so we define it here */ | |
38 | #define __NR_syscall 0 | |
39 | ||
40 | #undef SYS_ify | |
41 | #define SYS_ify(syscall_name) __NR_##syscall_name | |
42 | ||
847b055c AJ |
43 | #ifdef __ASSEMBLER__ |
44 | ||
45 | /* Linux uses a negative return value to indicate syscall errors, unlike | |
46 | most Unices, which use the condition codes' carry flag. | |
47 | ||
48 | Since version 2.1 the return value of a system call might be negative | |
49 | even if the call succeeded. E.g., the `lseek' system call might return | |
50 | a large offset. Therefore we must not anymore test for < 0, but test | |
51 | for a real error by making sure the value in gpr2 is a real error | |
19df733e | 52 | number. Linus said he will make sure that no syscall returns a value |
847b055c AJ |
53 | in -1 .. -4095 as a valid result so we can savely test with -4095. */ |
54 | ||
847b055c AJ |
55 | #undef PSEUDO |
56 | #define PSEUDO(name, syscall_name, args) \ | |
57 | .text; \ | |
d063d164 | 58 | ENTRY (name) \ |
ffa8d2a0 | 59 | DO_CALL (syscall_name, args); \ |
847b055c | 60 | lhi %r4,-4095 ; \ |
d063d164 | 61 | clr %r2,%r4 ; \ |
e6ebd2e4 | 62 | jnl SYSCALL_ERROR_LABEL |
847b055c AJ |
63 | |
64 | #undef PSEUDO_END | |
65 | #define PSEUDO_END(name) \ | |
66 | SYSCALL_ERROR_HANDLER; \ | |
67 | END (name) | |
68 | ||
441ee043 | 69 | #undef PSEUDO_NOERRNO |
9eb88290 UD |
70 | #define PSEUDO_NOERRNO(name, syscall_name, args) \ |
71 | .text; \ | |
d063d164 | 72 | ENTRY (name) \ |
9eb88290 UD |
73 | DO_CALL (syscall_name, args) |
74 | ||
75 | #undef PSEUDO_END_NOERRNO | |
76 | #define PSEUDO_END_NOERRNO(name) \ | |
77 | END (name) | |
78 | ||
137ffcdc UD |
79 | #undef PSEUDO_ERRVAL |
80 | #define PSEUDO_ERRVAL(name, syscall_name, args) \ | |
81 | .text; \ | |
d063d164 | 82 | ENTRY (name) \ |
137ffcdc UD |
83 | DO_CALL (syscall_name, args); \ |
84 | lcr %r2,%r2 | |
85 | ||
86 | #undef PSEUDO_END_ERRVAL | |
87 | #define PSEUDO_END_ERRVAL(name) \ | |
88 | END (name) | |
89 | ||
847b055c | 90 | #ifndef PIC |
e6ebd2e4 UD |
91 | # define SYSCALL_ERROR_LABEL 0f |
92 | # define SYSCALL_ERROR_HANDLER \ | |
93 | 0: basr %r1,0; \ | |
94 | 1: l %r1,2f-1b(%r1); \ | |
95 | br %r1; \ | |
96 | 2: .long syscall_error | |
847b055c | 97 | #else |
e6ebd2e4 UD |
98 | # if RTLD_PRIVATE_ERRNO |
99 | # define SYSCALL_ERROR_LABEL 0f | |
100 | # define SYSCALL_ERROR_HANDLER \ | |
101 | 0: basr %r1,0; \ | |
102 | 1: al %r1,2f-1b(%r1); \ | |
103 | lcr %r2,%r2; \ | |
104 | st %r2,0(%r1); \ | |
105 | lhi %r2,-1; \ | |
106 | br %r14; \ | |
96c82b3f | 107 | 2: .long rtld_errno-1b |
e6ebd2e4 | 108 | # elif defined _LIBC_REENTRANT |
d063d164 UD |
109 | # ifndef NOT_IN_libc |
110 | # define SYSCALL_ERROR_ERRNO __libc_errno | |
111 | # else | |
112 | # define SYSCALL_ERROR_ERRNO errno | |
113 | # endif | |
114 | # define SYSCALL_ERROR_LABEL 0f | |
115 | # define SYSCALL_ERROR_HANDLER \ | |
e6ebd2e4 UD |
116 | 0: lcr %r0,%r2; \ |
117 | basr %r1,0; \ | |
118 | 1: al %r1,2f-1b(%r1); \ | |
00c2b3b9 UD |
119 | l %r1,SYSCALL_ERROR_ERRNO@gotntpoff(%r1); \ |
120 | ear %r2,%a0; \ | |
e6ebd2e4 UD |
121 | st %r0,0(%r1,%r2); \ |
122 | lhi %r2,-1; \ | |
123 | br %r14; \ | |
124 | 2: .long _GLOBAL_OFFSET_TABLE_-1b | |
e6ebd2e4 UD |
125 | # else |
126 | # define SYSCALL_ERROR_LABEL 0f | |
127 | # define SYSCALL_ERROR_HANDLER \ | |
128 | 0: basr %r1,0; \ | |
129 | 1: al %r1,2f-1b(%r1); \ | |
130 | l %r1,errno@GOT(%r1); \ | |
131 | lcr %r2,%r2; \ | |
132 | st %r2,0(%r1); \ | |
133 | lhi %r2,-1; \ | |
134 | br %r14; \ | |
135 | 2: .long _GLOBAL_OFFSET_TABLE_-1b | |
136 | # endif /* _LIBC_REENTRANT */ | |
847b055c | 137 | #endif /* PIC */ |
847b055c AJ |
138 | |
139 | /* Linux takes system call arguments in registers: | |
140 | ||
141 | syscall number 1 call-clobbered | |
142 | arg 1 2 call-clobbered | |
143 | arg 2 3 call-clobbered | |
144 | arg 3 4 call-clobbered | |
145 | arg 4 5 call-clobbered | |
146 | arg 5 6 call-saved | |
8d2e6a03 | 147 | arg 6 7 call-saved |
847b055c AJ |
148 | |
149 | (Of course a function with say 3 arguments does not have entries for | |
150 | arguments 4 and 5.) | |
8d2e6a03 RM |
151 | For system calls with 6 parameters a stack operation is required |
152 | to load the 6th parameter to register 7. Call saved register 7 is | |
153 | moved to register 0 and back to avoid an additional stack frame. | |
847b055c AJ |
154 | */ |
155 | ||
ffa8d2a0 | 156 | #define DO_CALL(syscall, args) \ |
8d2e6a03 RM |
157 | .if args > 5; \ |
158 | lr %r0,%r7; \ | |
159 | l %r7,96(%r15); \ | |
160 | .endif; \ | |
1739d268 UD |
161 | .if SYS_ify (syscall) < 256; \ |
162 | svc SYS_ify (syscall); \ | |
163 | .else; \ | |
164 | lhi %r1,SYS_ify (syscall); \ | |
165 | svc 0; \ | |
8d2e6a03 RM |
166 | .endif; \ |
167 | .if args > 5; \ | |
168 | lr %r7,%r0; \ | |
1739d268 | 169 | .endif |
847b055c AJ |
170 | |
171 | #define ret \ | |
172 | br 14 | |
173 | ||
9eb88290 UD |
174 | #define ret_NOERRNO \ |
175 | br 14 | |
176 | ||
137ffcdc UD |
177 | #define ret_ERRVAL \ |
178 | br 14 | |
179 | ||
847b055c AJ |
180 | #endif /* __ASSEMBLER__ */ |
181 | ||
182 | #undef INLINE_SYSCALL | |
369b849f RM |
183 | #define INLINE_SYSCALL(name, nr, args...) \ |
184 | ({ \ | |
6aca81bb UD |
185 | unsigned int _ret = INTERNAL_SYSCALL (name, , nr, args); \ |
186 | if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_ret, ), 0)) \ | |
369b849f | 187 | { \ |
6aca81bb UD |
188 | __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, )); \ |
189 | _ret = 0xffffffff; \ | |
369b849f | 190 | } \ |
6aca81bb UD |
191 | (int) _ret; }) |
192 | ||
193 | #undef INTERNAL_SYSCALL_DECL | |
194 | #define INTERNAL_SYSCALL_DECL(err) do { } while (0) | |
847b055c | 195 | |
1739d268 UD |
196 | #undef INTERNAL_SYSCALL_DIRECT |
197 | #define INTERNAL_SYSCALL_DIRECT(name, err, nr, args...) \ | |
369b849f RM |
198 | ({ \ |
199 | DECLARGS_##nr(args) \ | |
d5b6c817 | 200 | register int _ret asm("2"); \ |
369b849f | 201 | asm volatile ( \ |
369b849f | 202 | "svc %b1\n\t" \ |
6aca81bb | 203 | : "=d" (_ret) \ |
d5b6c817 UD |
204 | : "i" (__NR_##name) ASMFMT_##nr \ |
205 | : "memory" ); \ | |
206 | _ret; }) | |
369b849f | 207 | |
1739d268 UD |
208 | #undef INTERNAL_SYSCALL_SVC0 |
209 | #define INTERNAL_SYSCALL_SVC0(name, err, nr, args...) \ | |
210 | ({ \ | |
211 | DECLARGS_##nr(args) \ | |
212 | register unsigned long _nr asm("1") = (unsigned long)(__NR_##name); \ | |
213 | register int _ret asm("2"); \ | |
214 | asm volatile ( \ | |
215 | "svc 0\n\t" \ | |
216 | : "=d" (_ret) \ | |
bbb5e55c UD |
217 | : "d" (_nr) ASMFMT_##nr \ |
218 | : "memory" ); \ | |
219 | _ret; }) | |
220 | ||
221 | #undef INTERNAL_SYSCALL_NCS | |
222 | #define INTERNAL_SYSCALL_NCS(no, err, nr, args...) \ | |
223 | ({ \ | |
224 | DECLARGS_##nr(args) \ | |
225 | register unsigned long _nr asm("1") = (unsigned long)(no); \ | |
226 | register int _ret asm("2"); \ | |
227 | asm volatile ( \ | |
228 | "svc 0\n\t" \ | |
229 | : "=d" (_ret) \ | |
230 | : "d" (_nr) ASMFMT_##nr \ | |
1739d268 UD |
231 | : "memory" ); \ |
232 | _ret; }) | |
233 | ||
234 | #undef INTERNAL_SYSCALL | |
235 | #define INTERNAL_SYSCALL(name, err, nr, args...) \ | |
236 | (((__NR_##name) < 256) ? \ | |
237 | INTERNAL_SYSCALL_DIRECT(name, err, nr, args) : \ | |
238 | INTERNAL_SYSCALL_SVC0(name, err,nr, args)) | |
239 | ||
369b849f | 240 | #undef INTERNAL_SYSCALL_ERROR_P |
6aca81bb UD |
241 | #define INTERNAL_SYSCALL_ERROR_P(val, err) \ |
242 | ((unsigned int) (val) >= 0xfffff001u) | |
369b849f RM |
243 | |
244 | #undef INTERNAL_SYSCALL_ERRNO | |
6aca81bb | 245 | #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) |
369b849f | 246 | |
847b055c AJ |
247 | #define DECLARGS_0() |
248 | #define DECLARGS_1(arg1) \ | |
d5b6c817 | 249 | register unsigned long gpr2 asm ("2") = (unsigned long)(arg1); |
847b055c AJ |
250 | #define DECLARGS_2(arg1, arg2) \ |
251 | DECLARGS_1(arg1) \ | |
d5b6c817 | 252 | register unsigned long gpr3 asm ("3") = (unsigned long)(arg2); |
847b055c AJ |
253 | #define DECLARGS_3(arg1, arg2, arg3) \ |
254 | DECLARGS_2(arg1, arg2) \ | |
d5b6c817 | 255 | register unsigned long gpr4 asm ("4") = (unsigned long)(arg3); |
847b055c AJ |
256 | #define DECLARGS_4(arg1, arg2, arg3, arg4) \ |
257 | DECLARGS_3(arg1, arg2, arg3) \ | |
d5b6c817 | 258 | register unsigned long gpr5 asm ("5") = (unsigned long)(arg4); |
847b055c AJ |
259 | #define DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \ |
260 | DECLARGS_4(arg1, arg2, arg3, arg4) \ | |
d5b6c817 | 261 | register unsigned long gpr6 asm ("6") = (unsigned long)(arg5); |
8d2e6a03 RM |
262 | #define DECLARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ |
263 | DECLARGS_5(arg1, arg2, arg3, arg4, arg5) \ | |
264 | register unsigned long gpr7 asm ("7") = (unsigned long)(arg6); | |
847b055c AJ |
265 | |
266 | #define ASMFMT_0 | |
d5b6c817 UD |
267 | #define ASMFMT_1 , "0" (gpr2) |
268 | #define ASMFMT_2 , "0" (gpr2), "d" (gpr3) | |
269 | #define ASMFMT_3 , "0" (gpr2), "d" (gpr3), "d" (gpr4) | |
270 | #define ASMFMT_4 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5) | |
271 | #define ASMFMT_5 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6) | |
8d2e6a03 | 272 | #define ASMFMT_6 , "0" (gpr2), "d" (gpr3), "d" (gpr4), "d" (gpr5), "d" (gpr6), "d" (gpr7) |
847b055c | 273 | |
0480c901 UD |
274 | #define CLOBBER_0 , "3", "4", "5" |
275 | #define CLOBBER_1 , "3", "4", "5" | |
276 | #define CLOBBER_2 , "4", "5" | |
277 | #define CLOBBER_3 , "5" | |
278 | #define CLOBBER_4 | |
279 | #define CLOBBER_5 | |
280 | #define CLOBBER_6 | |
281 | ||
282 | /* List of system calls which are supported as vsyscalls. */ | |
283 | #define HAVE_CLOCK_GETRES_VSYSCALL 1 | |
284 | #define HAVE_CLOCK_GETTIME_VSYSCALL 1 | |
285 | ||
286 | /* This version is for kernels that implement system calls that | |
287 | behave like function calls as far as register saving. | |
288 | It falls back to the syscall in the case that the vDSO doesn't | |
289 | exist or fails for ENOSYS */ | |
290 | #ifdef SHARED | |
291 | # define INLINE_VSYSCALL(name, nr, args...) \ | |
292 | ({ \ | |
293 | __label__ out; \ | |
294 | __label__ iserr; \ | |
295 | long int _ret; \ | |
296 | \ | |
297 | if (__vdso_##name != NULL) \ | |
298 | { \ | |
299 | _ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, , nr, ##args); \ | |
300 | if (!INTERNAL_SYSCALL_ERROR_P (_ret, )) \ | |
301 | goto out; \ | |
302 | if (INTERNAL_SYSCALL_ERRNO (_ret, ) != ENOSYS) \ | |
303 | goto iserr; \ | |
304 | } \ | |
305 | \ | |
306 | _ret = INTERNAL_SYSCALL (name, , nr, ##args); \ | |
307 | if (INTERNAL_SYSCALL_ERROR_P (_ret, )) \ | |
308 | { \ | |
309 | iserr: \ | |
d063d164 UD |
310 | __set_errno (INTERNAL_SYSCALL_ERRNO (_ret, )); \ |
311 | _ret = -1L; \ | |
0480c901 UD |
312 | } \ |
313 | out: \ | |
314 | (int) _ret; \ | |
315 | }) | |
316 | #else | |
317 | # define INLINE_VSYSCALL(name, nr, args...) \ | |
318 | INLINE_SYSCALL (name, nr, ##args) | |
319 | #endif | |
320 | ||
321 | #ifdef SHARED | |
322 | # define INTERNAL_VSYSCALL(name, err, nr, args...) \ | |
323 | ({ \ | |
324 | __label__ out; \ | |
325 | long int _ret; \ | |
326 | \ | |
327 | if (__vdso_##name != NULL) \ | |
328 | { \ | |
329 | _ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \ | |
330 | if (!INTERNAL_SYSCALL_ERROR_P (_ret, err) \ | |
331 | || INTERNAL_SYSCALL_ERRNO (_ret, err) != ENOSYS) \ | |
332 | goto out; \ | |
333 | } \ | |
334 | _ret = INTERNAL_SYSCALL (name, err, nr, ##args); \ | |
335 | out: \ | |
336 | _ret; \ | |
337 | }) | |
338 | #else | |
339 | # define INTERNAL_VSYSCALL(name, err, nr, args...) \ | |
340 | INTERNAL_SYSCALL (name, err, nr, ##args) | |
341 | #endif | |
342 | ||
343 | /* This version is for internal uses when there is no desire | |
344 | to set errno */ | |
345 | #define INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK(name, err, nr, args...) \ | |
346 | ({ \ | |
347 | long int _ret = ENOSYS; \ | |
348 | \ | |
349 | if (__vdso_##name != NULL) \ | |
350 | _ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \ | |
351 | else \ | |
352 | err = 1 << 28; \ | |
353 | _ret; \ | |
354 | }) | |
355 | ||
356 | #define INTERNAL_VSYSCALL_NCS(fn, err, nr, args...) \ | |
357 | ({ \ | |
358 | DECLARGS_##nr(args) \ | |
359 | register long _ret asm("2"); \ | |
360 | asm volatile ( \ | |
19df733e | 361 | "lr 10,14\n\t" \ |
0480c901 | 362 | "basr 14,%1\n\t" \ |
19df733e | 363 | "lr 14,10\n\t" \ |
0480c901 UD |
364 | : "=d" (_ret) \ |
365 | : "d" (fn) ASMFMT_##nr \ | |
19df733e | 366 | : "cc", "memory", "0", "1", "10" CLOBBER_##nr); \ |
0480c901 | 367 | _ret; }) |
00c2b3b9 UD |
368 | |
369 | /* Pointer mangling support. */ | |
370 | #if defined NOT_IN_libc && defined IS_IN_rtld | |
371 | /* We cannot use the thread descriptor because in ld.so we use setjmp | |
372 | earlier than the descriptor is initialized. */ | |
373 | #else | |
374 | /* For the time being just use stack_guard rather than a separate | |
375 | pointer_guard. */ | |
376 | # ifdef __ASSEMBLER__ | |
377 | # define PTR_MANGLE(reg, tmpreg) \ | |
378 | ear tmpreg,%a0; \ | |
379 | x reg,STACK_GUARD(tmpreg) | |
305bb37e UD |
380 | # define PTR_MANGLE2(reg, tmpreg) \ |
381 | x reg,STACK_GUARD(tmpreg) | |
00c2b3b9 UD |
382 | # define PTR_DEMANGLE(reg, tmpreg) PTR_MANGLE (reg, tmpreg) |
383 | # else | |
384 | # define PTR_MANGLE(var) \ | |
385 | (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ()) | |
386 | # define PTR_DEMANGLE(var) PTR_MANGLE (var) | |
387 | # endif | |
388 | #endif | |
389 | ||
847b055c | 390 | #endif /* _LINUX_S390_SYSDEP_H */ |