(INTERNAL_SYSCALL, INTERNAL_SYSCALL_ERROR_P, INTERNAL_SYSCALL_ERRNO):
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / ia64 / sysdep.h
1 /* Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Written by Jes Sorensen, <Jes.Sorensen@cern.ch>, April 1999.
4    Based on code originally written by David Mosberger-Tang
5
6    The GNU C Library is free software; you can redistribute it and/or
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.
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
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #ifndef _LINUX_IA64_SYSDEP_H
22 #define _LINUX_IA64_SYSDEP_H 1
23
24 #include <sysdeps/unix/sysdep.h>
25 #include <sysdeps/ia64/sysdep.h>
26
27 /* For Linux we can use the system call table in the header file
28         /usr/include/asm/unistd.h
29    of the kernel.  But these symbols do not follow the SYS_* syntax
30    so we have to redefine the `SYS_ify' macro here.  */
31 #undef SYS_ify
32 #ifdef __STDC__
33 # define SYS_ify(syscall_name)  __NR_##syscall_name
34 #else
35 # define SYS_ify(syscall_name)  __NR_/**/syscall_name
36 #endif
37
38 /* This is a kludge to make syscalls.list find these under the names
39    pread and pwrite, since some kernel headers define those names
40    and some define the *64 names for the same system calls.  */
41 #if !defined __NR_pread && defined __NR_pread64
42 # define __NR_pread __NR_pread64
43 #endif
44 #if !defined __NR_pwrite && defined __NR_pwrite64
45 # define __NR_pwrite __NR_pwrite64
46 #endif
47
48 #ifdef __ASSEMBLER__
49
50 #undef CALL_MCOUNT
51 #ifdef PROF
52 # define CALL_MCOUNT                                                    \
53         .data;                                                          \
54 1:      data8 0;        /* XXX fixme: use .xdata8 once labels work */   \
55         .previous;                                                      \
56         .prologue;                                                      \
57         .save ar.pfs, r40;                                              \
58         alloc out0 = ar.pfs, 8, 0, 4, 0;                                \
59         mov out1 = gp;                                                  \
60         .save rp, out2;                                                 \
61         mov out2 = rp;                                                  \
62         .body;                                                          \
63         ;;                                                              \
64         addl out3 = @ltoff(1b), gp;                                     \
65         br.call.sptk.many rp = _mcount                                  \
66         ;;
67 #else
68 # define CALL_MCOUNT    /* Do nothing. */
69 #endif
70
71 /* Linux uses a negative return value to indicate syscall errors, unlike
72    most Unices, which use the condition codes' carry flag.
73
74    Since version 2.1 the return value of a system call might be negative
75    even if the call succeeded.  E.g., the `lseek' system call might return
76    a large offset.  Therefore we must not anymore test for < 0, but test
77    for a real error by making sure the value in %d0 is a real error
78    number.  Linus said he will make sure the no syscall returns a value
79    in -1 .. -4095 as a valid result so we can savely test with -4095.  */
80
81 /* We don't want the label for the error handler to be visible in the symbol
82    table when we define it here.  */
83 #define SYSCALL_ERROR_LABEL __syscall_error
84
85 #undef PSEUDO
86 #define PSEUDO(name, syscall_name, args)        \
87   ENTRY(name)                                   \
88     DO_CALL (SYS_ify(syscall_name));            \
89         cmp.eq p6,p0=-1,r10;                    \
90 (p6)    br.cond.spnt.few __syscall_error;
91
92 #define DO_CALL(num)                            \
93         mov r15=num;                            \
94         break __BREAK_SYSCALL;
95
96 #undef PSEUDO_END
97 #define PSEUDO_END(name)        .endp C_SYMBOL_NAME(name);
98
99 #undef END
100 #define END(name)                                               \
101         .size   C_SYMBOL_NAME(name), . - C_SYMBOL_NAME(name) ;  \
102         .endp   C_SYMBOL_NAME(name)
103
104 #define ret                     br.ret.sptk.few b0
105
106 #else /* not __ASSEMBLER__ */
107
108 /* On IA-64 we have stacked registers for passing arguments.  The
109    "out" registers end up being the called function's "in"
110    registers.
111
112    Also, since we have plenty of registers we have two return values
113    from a syscall.  r10 is set to -1 on error, whilst r8 contains the
114    (non-negative) errno on error or the return value on success.
115  */
116 #undef INLINE_SYSCALL
117 #define INLINE_SYSCALL(name, nr, args...)                       \
118   ({                                                            \
119     register long _r8 asm ("r8");                               \
120     register long _r10 asm ("r10");                             \
121     register long _r15 asm ("r15") = __NR_##name;               \
122     long _retval;                                               \
123     LOAD_ARGS_##nr (args);                                      \
124     __asm __volatile ("break %3;;\n\t"                          \
125                       : "=r" (_r8), "=r" (_r10), "=r" (_r15)    \
126                       : "i" (__BREAK_SYSCALL), "2" (_r15)       \
127                         ASM_ARGS_##nr                           \
128                       : "memory" ASM_CLOBBERS_##nr);            \
129     _retval = _r8;                                              \
130     if (_r10 == -1)                                             \
131       {                                                         \
132         __set_errno (_retval);                                  \
133         _retval = -1;                                           \
134       }                                                         \
135     _retval; })
136
137 #undef INTERNAL_SYSCALL_DECL
138 #define INTERNAL_SYSCALL_DECL(err) long int err
139
140 #undef INTERNAL_SYSCALL
141 #define INTERNAL_SYSCALL(name, err, nr, args...)                \
142   ({                                                            \
143     register long _r8 asm ("r8");                               \
144     register long _r10 asm ("r10");                             \
145     register long _r15 asm ("r15") = __NR_##name;               \
146     long _retval;                                               \
147     LOAD_ARGS_##nr (args);                                      \
148     __asm __volatile ("break %3;;\n\t"                          \
149                       : "=r" (_r8), "=r" (_r10), "=r" (_r15)    \
150                       : "i" (__BREAK_SYSCALL), "2" (_r15)       \
151                         ASM_ARGS_##nr                           \
152                       : "memory" ASM_CLOBBERS_##nr);            \
153     _retval = _r8;                                              \
154     err = _r10;                                                 \
155     _retval; })
156
157 #undef INTERNAL_SYSCALL_ERROR_P
158 #define INTERNAL_SYSCALL_ERROR_P(val, err)      (err == -1)
159
160 #undef INTERNAL_SYSCALL_ERRNO
161 #define INTERNAL_SYSCALL_ERRNO(val, err)        (val)
162
163 #define LOAD_ARGS_0()   do { } while (0)
164 #define LOAD_ARGS_1(out0)                               \
165   register long _out0 asm ("out0") = (long) (out0);     \
166   LOAD_ARGS_0 ()
167 #define LOAD_ARGS_2(out0, out1)                         \
168   register long _out1 asm ("out1") = (long) (out1);     \
169   LOAD_ARGS_1 (out0)
170 #define LOAD_ARGS_3(out0, out1, out2)                   \
171   register long _out2 asm ("out2") = (long) (out2);     \
172   LOAD_ARGS_2 (out0, out1)
173 #define LOAD_ARGS_4(out0, out1, out2, out3)             \
174   register long _out3 asm ("out3") = (long) (out3);     \
175   LOAD_ARGS_3 (out0, out1, out2)
176 #define LOAD_ARGS_5(out0, out1, out2, out3, out4)       \
177   register long _out4 asm ("out4") = (long) (out4);     \
178   LOAD_ARGS_4 (out0, out1, out2, out3)
179
180 #define ASM_ARGS_0
181 #define ASM_ARGS_1      ASM_ARGS_0, "r" (_out0)
182 #define ASM_ARGS_2      ASM_ARGS_1, "r" (_out1)
183 #define ASM_ARGS_3      ASM_ARGS_2, "r" (_out2)
184 #define ASM_ARGS_4      ASM_ARGS_3, "r" (_out3)
185 #define ASM_ARGS_5      ASM_ARGS_4, "r" (_out4)
186
187 #define ASM_CLOBBERS_0  ASM_CLOBBERS_1, "out0"
188 #define ASM_CLOBBERS_1  ASM_CLOBBERS_2, "out1"
189 #define ASM_CLOBBERS_2  ASM_CLOBBERS_3, "out2"
190 #define ASM_CLOBBERS_3  ASM_CLOBBERS_4, "out3"
191 #define ASM_CLOBBERS_4  ASM_CLOBBERS_5, "out4"
192 #define ASM_CLOBBERS_5  , "out5", "out6", "out7",                       \
193   /* Non-stacked integer registers, minus r8, r10, r15.  */             \
194   "r2", "r3", "r9", "r11", "r12", "r13", "r14", "r16", "r17", "r18",    \
195   "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27",        \
196   "r28", "r29", "r30", "r31",                                           \
197   /* Predicate registers.  */                                           \
198   "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15",     \
199   /* Non-rotating fp registers.  */                                     \
200   "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",     \
201   /* Branch registers.  */                                              \
202   "b6", "b7"
203
204 #endif /* not __ASSEMBLER__ */
205
206 #endif /* linux/ia64/sysdep.h */