]>
Commit | Line | Data |
---|---|---|
cbbbb188 | 1 | /* Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006 |
00c2b3b9 | 2 | Free Software Foundation, Inc. |
f1d86a93 UD |
3 | This file is part of the GNU C Library. |
4 | Written by Jes Sorensen, <Jes.Sorensen@cern.ch>, April 1999. | |
5 | Based on code originally written by David Mosberger-Tang | |
6 | ||
7 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
8 | modify it under the terms of the GNU Lesser General Public |
9 | License as published by the Free Software Foundation; either | |
10 | version 2.1 of the License, or (at your option) any later version. | |
f1d86a93 UD |
11 | |
12 | The GNU C Library is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 15 | Lesser General Public License for more details. |
f1d86a93 | 16 | |
41bdb6e2 AJ |
17 | You should have received a copy of the GNU Lesser General Public |
18 | License along with the GNU C Library; if not, write to the Free | |
19 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
20 | 02111-1307 USA. */ | |
f1d86a93 | 21 | |
a4baf360 UD |
22 | #ifndef _LINUX_IA64_SYSDEP_H |
23 | #define _LINUX_IA64_SYSDEP_H 1 | |
24 | ||
f1d86a93 | 25 | #include <sysdeps/unix/sysdep.h> |
ed80b9ee | 26 | #include <sysdeps/ia64/sysdep.h> |
c776b3d7 UD |
27 | #include <dl-sysdep.h> |
28 | #include <tls.h> | |
f1d86a93 | 29 | |
c9002c1b UD |
30 | /* As of GAS v2.4.90.0.7, including a ".align" directive inside a |
31 | function will cause bad unwind info to be emitted (GAS doesn't know | |
32 | how to account for the padding introduced by the .align directive). | |
33 | Turning on this macro will work around this bug by introducing the | |
34 | necessary padding explicitly. */ | |
35 | #define GAS_ALIGN_BREAKS_UNWIND_INFO | |
36 | ||
f1d86a93 UD |
37 | /* For Linux we can use the system call table in the header file |
38 | /usr/include/asm/unistd.h | |
39 | of the kernel. But these symbols do not follow the SYS_* syntax | |
40 | so we have to redefine the `SYS_ify' macro here. */ | |
41 | #undef SYS_ify | |
42 | #ifdef __STDC__ | |
43 | # define SYS_ify(syscall_name) __NR_##syscall_name | |
44 | #else | |
45 | # define SYS_ify(syscall_name) __NR_/**/syscall_name | |
46 | #endif | |
47 | ||
1c120cb8 RM |
48 | /* This is a kludge to make syscalls.list find these under the names |
49 | pread and pwrite, since some kernel headers define those names | |
50 | and some define the *64 names for the same system calls. */ | |
51 | #if !defined __NR_pread && defined __NR_pread64 | |
52 | # define __NR_pread __NR_pread64 | |
53 | #endif | |
54 | #if !defined __NR_pwrite && defined __NR_pwrite64 | |
55 | # define __NR_pwrite __NR_pwrite64 | |
56 | #endif | |
57 | ||
a12ce44f UD |
58 | /* This is to help the old kernel headers where __NR_semtimedop is not |
59 | available. */ | |
60 | #ifndef __NR_semtimedop | |
61 | # define __NR_semtimedop 1247 | |
62 | #endif | |
63 | ||
c776b3d7 UD |
64 | #if defined USE_DL_SYSINFO \ |
65 | && (!defined NOT_IN_libc \ | |
66 | || defined IS_IN_libpthread || defined IS_IN_librt) | |
67 | # define IA64_USE_NEW_STUB | |
68 | #else | |
69 | # undef IA64_USE_NEW_STUB | |
70 | #endif | |
71 | ||
f1d86a93 UD |
72 | #ifdef __ASSEMBLER__ |
73 | ||
3107c0c5 UD |
74 | #undef CALL_MCOUNT |
75 | #ifdef PROF | |
0a45b76c UD |
76 | # define CALL_MCOUNT \ |
77 | .data; \ | |
78 | 1: data8 0; /* XXX fixme: use .xdata8 once labels work */ \ | |
79 | .previous; \ | |
80 | .prologue; \ | |
81 | .save ar.pfs, r40; \ | |
82 | alloc out0 = ar.pfs, 8, 0, 4, 0; \ | |
83 | mov out1 = gp; \ | |
84 | .save rp, out2; \ | |
85 | mov out2 = rp; \ | |
86 | .body; \ | |
87 | ;; \ | |
88 | addl out3 = @ltoff(1b), gp; \ | |
89 | br.call.sptk.many rp = _mcount \ | |
3107c0c5 UD |
90 | ;; |
91 | #else | |
92 | # define CALL_MCOUNT /* Do nothing. */ | |
93 | #endif | |
94 | ||
f1d86a93 UD |
95 | /* Linux uses a negative return value to indicate syscall errors, unlike |
96 | most Unices, which use the condition codes' carry flag. | |
97 | ||
98 | Since version 2.1 the return value of a system call might be negative | |
99 | even if the call succeeded. E.g., the `lseek' system call might return | |
100 | a large offset. Therefore we must not anymore test for < 0, but test | |
101 | for a real error by making sure the value in %d0 is a real error | |
102 | number. Linus said he will make sure the no syscall returns a value | |
103 | in -1 .. -4095 as a valid result so we can savely test with -4095. */ | |
104 | ||
105 | /* We don't want the label for the error handler to be visible in the symbol | |
106 | table when we define it here. */ | |
107 | #define SYSCALL_ERROR_LABEL __syscall_error | |
108 | ||
f1d86a93 UD |
109 | #undef PSEUDO |
110 | #define PSEUDO(name, syscall_name, args) \ | |
111 | ENTRY(name) \ | |
112 | DO_CALL (SYS_ify(syscall_name)); \ | |
131fd126 | 113 | cmp.eq p6,p0=-1,r10; \ |
f1d86a93 UD |
114 | (p6) br.cond.spnt.few __syscall_error; |
115 | ||
c776b3d7 | 116 | #define DO_CALL_VIA_BREAK(num) \ |
f1d86a93 | 117 | mov r15=num; \ |
c776b3d7 UD |
118 | break __BREAK_SYSCALL |
119 | ||
120 | #ifdef IA64_USE_NEW_STUB | |
121 | # ifdef SHARED | |
122 | # define DO_CALL(num) \ | |
123 | .prologue; \ | |
124 | adds r2 = SYSINFO_OFFSET, r13;; \ | |
125 | ld8 r2 = [r2]; \ | |
126 | .save ar.pfs, r11; \ | |
127 | mov r11 = ar.pfs;; \ | |
128 | .body; \ | |
129 | mov r15 = num; \ | |
130 | mov b7 = r2; \ | |
131 | br.call.sptk.many b6 = b7;; \ | |
132 | .restore sp; \ | |
133 | mov ar.pfs = r11; \ | |
134 | .prologue; \ | |
135 | .body | |
136 | # else /* !SHARED */ | |
137 | # define DO_CALL(num) \ | |
138 | .prologue; \ | |
139 | mov r15 = num; \ | |
140 | movl r2 = _dl_sysinfo;; \ | |
141 | ld8 r2 = [r2]; \ | |
142 | .save ar.pfs, r11; \ | |
143 | mov r11 = ar.pfs;; \ | |
144 | .body; \ | |
145 | mov b7 = r2; \ | |
146 | br.call.sptk.many b6 = b7;; \ | |
147 | .restore sp; \ | |
148 | mov ar.pfs = r11; \ | |
149 | .prologue; \ | |
150 | .body | |
151 | # endif | |
152 | #else | |
153 | # define DO_CALL(num) DO_CALL_VIA_BREAK(num) | |
154 | #endif | |
f1d86a93 UD |
155 | |
156 | #undef PSEUDO_END | |
157 | #define PSEUDO_END(name) .endp C_SYMBOL_NAME(name); | |
158 | ||
9eb88290 UD |
159 | #undef PSEUDO_NOERRNO |
160 | #define PSEUDO_NOERRNO(name, syscall_name, args) \ | |
161 | ENTRY(name) \ | |
162 | DO_CALL (SYS_ify(syscall_name)); | |
163 | ||
164 | #undef PSEUDO_END_NOERRNO | |
165 | #define PSEUDO_END_NOERRNO(name) .endp C_SYMBOL_NAME(name); | |
166 | ||
bfef9264 UD |
167 | #undef PSEUDO_ERRVAL |
168 | #define PSEUDO_ERRVAL(name, syscall_name, args) \ | |
5f66b766 | 169 | ENTRY(name) \ |
bfef9264 UD |
170 | DO_CALL (SYS_ify(syscall_name)); \ |
171 | cmp.eq p6,p0=-1,r10; \ | |
172 | (p6) mov r10=r8; | |
173 | ||
174 | ||
175 | #undef PSEUDO_END_ERRVAL | |
176 | #define PSEUDO_END_ERRVAL(name) .endp C_SYMBOL_NAME(name); | |
177 | ||
f1d86a93 UD |
178 | #undef END |
179 | #define END(name) \ | |
180 | .size C_SYMBOL_NAME(name), . - C_SYMBOL_NAME(name) ; \ | |
181 | .endp C_SYMBOL_NAME(name) | |
182 | ||
183 | #define ret br.ret.sptk.few b0 | |
6ea5c103 | 184 | #define ret_NOERRNO ret |
f38afd78 | 185 | #define ret_ERRVAL ret |
f1d86a93 UD |
186 | |
187 | #else /* not __ASSEMBLER__ */ | |
188 | ||
b5ec5617 UD |
189 | #define BREAK_INSN_1(num) "break " #num ";;\n\t" |
190 | #define BREAK_INSN(num) BREAK_INSN_1(num) | |
191 | ||
131fd126 UD |
192 | /* On IA-64 we have stacked registers for passing arguments. The |
193 | "out" registers end up being the called function's "in" | |
194 | registers. | |
195 | ||
196 | Also, since we have plenty of registers we have two return values | |
197 | from a syscall. r10 is set to -1 on error, whilst r8 contains the | |
198 | (non-negative) errno on error or the return value on success. | |
199 | */ | |
c776b3d7 UD |
200 | |
201 | #ifdef IA64_USE_NEW_STUB | |
202 | ||
4ff389fe | 203 | # define DO_INLINE_SYSCALL_NCS(name, nr, args...) \ |
2edb61e3 UD |
204 | LOAD_ARGS_##nr (args) \ |
205 | register long _r8 __asm ("r8"); \ | |
206 | register long _r10 __asm ("r10"); \ | |
207 | register long _r15 __asm ("r15") = name; \ | |
cbbbb188 | 208 | register void *_b7 __asm ("b7") = ((tcbhead_t *)__thread_self)->__private;\ |
2edb61e3 UD |
209 | long _retval; \ |
210 | LOAD_REGS_##nr \ | |
211 | /* \ | |
212 | * Don't specify any unwind info here. We mark ar.pfs as \ | |
213 | * clobbered. This will force the compiler to save ar.pfs \ | |
214 | * somewhere and emit appropriate unwind info for that save. \ | |
215 | */ \ | |
216 | __asm __volatile ("br.call.sptk.many b6=%0;;\n" \ | |
217 | : "=b"(_b7), "=r" (_r8), "=r" (_r10), "=r" (_r15) \ | |
218 | ASM_OUTARGS_##nr \ | |
219 | : "0" (_b7), "3" (_r15) ASM_ARGS_##nr \ | |
220 | : "memory", "ar.pfs" ASM_CLOBBERS_##nr); \ | |
c776b3d7 UD |
221 | _retval = _r8; |
222 | ||
223 | #else /* !IA64_USE_NEW_STUB */ | |
224 | ||
4ff389fe | 225 | # define DO_INLINE_SYSCALL_NCS(name, nr, args...) \ |
cfcc576a | 226 | LOAD_ARGS_##nr (args) \ |
131fd126 UD |
227 | register long _r8 asm ("r8"); \ |
228 | register long _r10 asm ("r10"); \ | |
2edb61e3 | 229 | register long _r15 asm ("r15") = name; \ |
131fd126 | 230 | long _retval; \ |
cfcc576a | 231 | LOAD_REGS_##nr \ |
b5ec5617 | 232 | __asm __volatile (BREAK_INSN (__BREAK_SYSCALL) \ |
c776b3d7 | 233 | : "=r" (_r8), "=r" (_r10), "=r" (_r15) \ |
b5ec5617 | 234 | ASM_OUTARGS_##nr \ |
c776b3d7 UD |
235 | : "2" (_r15) ASM_ARGS_##nr \ |
236 | : "memory" ASM_CLOBBERS_##nr); \ | |
237 | _retval = _r8; | |
238 | ||
239 | #endif /* !IA64_USE_NEW_STUB */ | |
240 | ||
4ff389fe UD |
241 | #define DO_INLINE_SYSCALL(name, nr, args...) \ |
242 | DO_INLINE_SYSCALL_NCS (__NR_##name, nr, ##args) | |
243 | ||
c776b3d7 | 244 | #undef INLINE_SYSCALL |
5f66b766 UD |
245 | #define INLINE_SYSCALL(name, nr, args...) \ |
246 | ({ \ | |
247 | DO_INLINE_SYSCALL_NCS (__NR_##name, nr, args) \ | |
248 | if (_r10 == -1) \ | |
249 | { \ | |
250 | __set_errno (_retval); \ | |
251 | _retval = -1; \ | |
252 | } \ | |
131fd126 UD |
253 | _retval; }) |
254 | ||
6aca81bb UD |
255 | #undef INTERNAL_SYSCALL_DECL |
256 | #define INTERNAL_SYSCALL_DECL(err) long int err | |
257 | ||
131fd126 | 258 | #undef INTERNAL_SYSCALL |
2edb61e3 | 259 | #define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ |
c776b3d7 | 260 | ({ \ |
5f66b766 | 261 | DO_INLINE_SYSCALL_NCS (name, nr, args) \ |
c776b3d7 | 262 | err = _r10; \ |
131fd126 | 263 | _retval; }) |
2edb61e3 UD |
264 | #define INTERNAL_SYSCALL(name, err, nr, args...) \ |
265 | INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args) | |
131fd126 UD |
266 | |
267 | #undef INTERNAL_SYSCALL_ERROR_P | |
6aca81bb | 268 | #define INTERNAL_SYSCALL_ERROR_P(val, err) (err == -1) |
131fd126 UD |
269 | |
270 | #undef INTERNAL_SYSCALL_ERRNO | |
6aca81bb | 271 | #define INTERNAL_SYSCALL_ERRNO(val, err) (val) |
131fd126 | 272 | |
cfcc576a UD |
273 | #define LOAD_ARGS_0() |
274 | #define LOAD_REGS_0 | |
275 | #define LOAD_ARGS_1(a1) \ | |
276 | long _arg1 = (long) (a1); \ | |
131fd126 | 277 | LOAD_ARGS_0 () |
cfcc576a UD |
278 | #define LOAD_REGS_1 \ |
279 | register long _out0 asm ("out0") = _arg1; \ | |
280 | LOAD_REGS_0 | |
281 | #define LOAD_ARGS_2(a1, a2) \ | |
282 | long _arg2 = (long) (a2); \ | |
283 | LOAD_ARGS_1 (a1) | |
284 | #define LOAD_REGS_2 \ | |
285 | register long _out1 asm ("out1") = _arg2; \ | |
286 | LOAD_REGS_1 | |
287 | #define LOAD_ARGS_3(a1, a2, a3) \ | |
288 | long _arg3 = (long) (a3); \ | |
289 | LOAD_ARGS_2 (a1, a2) | |
290 | #define LOAD_REGS_3 \ | |
291 | register long _out2 asm ("out2") = _arg3; \ | |
292 | LOAD_REGS_2 | |
293 | #define LOAD_ARGS_4(a1, a2, a3, a4) \ | |
294 | long _arg4 = (long) (a4); \ | |
295 | LOAD_ARGS_3 (a1, a2, a3) | |
296 | #define LOAD_REGS_4 \ | |
297 | register long _out3 asm ("out3") = _arg4; \ | |
298 | LOAD_REGS_3 | |
299 | #define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ | |
300 | long _arg5 = (long) (a5); \ | |
301 | LOAD_ARGS_4 (a1, a2, a3, a4) | |
302 | #define LOAD_REGS_5 \ | |
303 | register long _out4 asm ("out4") = _arg5; \ | |
304 | LOAD_REGS_4 | |
305 | #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \ | |
306 | long _arg6 = (long) (a6); \ | |
307 | LOAD_ARGS_5 (a1, a2, a3, a4, a5) | |
308 | #define LOAD_REGS_6 \ | |
309 | register long _out5 asm ("out5") = _arg6; \ | |
310 | LOAD_REGS_5 | |
131fd126 | 311 | |
b5ec5617 UD |
312 | #define ASM_OUTARGS_0 |
313 | #define ASM_OUTARGS_1 ASM_OUTARGS_0, "=r" (_out0) | |
314 | #define ASM_OUTARGS_2 ASM_OUTARGS_1, "=r" (_out1) | |
315 | #define ASM_OUTARGS_3 ASM_OUTARGS_2, "=r" (_out2) | |
316 | #define ASM_OUTARGS_4 ASM_OUTARGS_3, "=r" (_out3) | |
317 | #define ASM_OUTARGS_5 ASM_OUTARGS_4, "=r" (_out4) | |
318 | #define ASM_OUTARGS_6 ASM_OUTARGS_5, "=r" (_out5) | |
319 | ||
c776b3d7 UD |
320 | #ifdef IA64_USE_NEW_STUB |
321 | #define ASM_ARGS_0 | |
322 | #define ASM_ARGS_1 ASM_ARGS_0, "4" (_out0) | |
323 | #define ASM_ARGS_2 ASM_ARGS_1, "5" (_out1) | |
324 | #define ASM_ARGS_3 ASM_ARGS_2, "6" (_out2) | |
325 | #define ASM_ARGS_4 ASM_ARGS_3, "7" (_out3) | |
326 | #define ASM_ARGS_5 ASM_ARGS_4, "8" (_out4) | |
327 | #define ASM_ARGS_6 ASM_ARGS_5, "9" (_out5) | |
328 | #else | |
131fd126 | 329 | #define ASM_ARGS_0 |
b5ec5617 UD |
330 | #define ASM_ARGS_1 ASM_ARGS_0, "3" (_out0) |
331 | #define ASM_ARGS_2 ASM_ARGS_1, "4" (_out1) | |
332 | #define ASM_ARGS_3 ASM_ARGS_2, "5" (_out2) | |
333 | #define ASM_ARGS_4 ASM_ARGS_3, "6" (_out3) | |
334 | #define ASM_ARGS_5 ASM_ARGS_4, "7" (_out4) | |
335 | #define ASM_ARGS_6 ASM_ARGS_5, "8" (_out5) | |
c776b3d7 | 336 | #endif |
131fd126 UD |
337 | |
338 | #define ASM_CLOBBERS_0 ASM_CLOBBERS_1, "out0" | |
339 | #define ASM_CLOBBERS_1 ASM_CLOBBERS_2, "out1" | |
340 | #define ASM_CLOBBERS_2 ASM_CLOBBERS_3, "out2" | |
341 | #define ASM_CLOBBERS_3 ASM_CLOBBERS_4, "out3" | |
342 | #define ASM_CLOBBERS_4 ASM_CLOBBERS_5, "out4" | |
b33e6163 | 343 | #define ASM_CLOBBERS_5 ASM_CLOBBERS_6, "out5" |
c776b3d7 | 344 | #define ASM_CLOBBERS_6_COMMON , "out6", "out7", \ |
131fd126 UD |
345 | /* Non-stacked integer registers, minus r8, r10, r15. */ \ |
346 | "r2", "r3", "r9", "r11", "r12", "r13", "r14", "r16", "r17", "r18", \ | |
347 | "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", \ | |
348 | "r28", "r29", "r30", "r31", \ | |
349 | /* Predicate registers. */ \ | |
350 | "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15", \ | |
351 | /* Non-rotating fp registers. */ \ | |
352 | "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ | |
353 | /* Branch registers. */ \ | |
c776b3d7 UD |
354 | "b6" |
355 | ||
356 | #ifdef IA64_USE_NEW_STUB | |
357 | # define ASM_CLOBBERS_6 ASM_CLOBBERS_6_COMMON | |
358 | #else | |
359 | # define ASM_CLOBBERS_6 ASM_CLOBBERS_6_COMMON , "b7" | |
360 | #endif | |
f1d86a93 UD |
361 | |
362 | #endif /* not __ASSEMBLER__ */ | |
a4baf360 | 363 | |
00c2b3b9 UD |
364 | /* Pointer mangling support. */ |
365 | #if defined NOT_IN_libc && defined IS_IN_rtld | |
366 | /* We cannot use the thread descriptor because in ld.so we use setjmp | |
367 | earlier than the descriptor is initialized. */ | |
368 | #else | |
369 | # ifdef __ASSEMBLER__ | |
370 | # define PTR_MANGLE(reg, tmpreg) \ | |
371 | add tmpreg=-16,r13 \ | |
372 | ;; \ | |
373 | ld8 tmpreg=[tmpreg] \ | |
374 | ;; \ | |
375 | xor reg=reg, tmpreg | |
376 | # define PTR_DEMANGLE(reg, tmpreg) PTR_MANGLE (reg, tmpreg) | |
377 | # else | |
378 | # define PTR_MANGLE(var) \ | |
379 | (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ()) | |
380 | # define PTR_DEMANGLE(var) PTR_MANGLE (var) | |
381 | # endif | |
382 | #endif | |
383 | ||
a4baf360 | 384 | #endif /* linux/ia64/sysdep.h */ |