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