2006-01-08 Roland McGrath <roland@redhat.com>
[glibc-ports.git] / sysdeps / unix / sysv / linux / m68k / sysdep.h
blob091dfc9c7d3e0c06c42472c565c438a8d1001087
1 /* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Written by Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>,
4 December 1995.
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.
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.
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. */
21 #include <sysdeps/unix/sysdep.h>
22 #include <sysdeps/m68k/sysdep.h>
24 /* Defines RTLD_PRIVATE_ERRNO. */
25 #include <dl-sysdep.h>
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
38 #ifdef __ASSEMBLER__
40 /* Linux uses a negative return value to indicate syscall errors, unlike
41 most Unices, which use the condition codes' carry flag.
43 Since version 2.1 the return value of a system call might be negative
44 even if the call succeeded. E.g., the `lseek' system call might return
45 a large offset. Therefore we must not anymore test for < 0, but test
46 for a real error by making sure the value in %d0 is a real error
47 number. Linus said he will make sure the no syscall returns a value
48 in -1 .. -4095 as a valid result so we can savely test with -4095. */
50 /* We don't want the label for the error handler to be visible in the symbol
51 table when we define it here. */
52 #ifdef PIC
53 #define SYSCALL_ERROR_LABEL .Lsyscall_error
54 #else
55 #define SYSCALL_ERROR_LABEL __syscall_error
56 #endif
58 #undef PSEUDO
59 #define PSEUDO(name, syscall_name, args) \
60 .text; \
61 ENTRY (name) \
62 DO_CALL (syscall_name, args); \
63 cmp.l &-4095, %d0; \
64 jcc SYSCALL_ERROR_LABEL
66 #undef PSEUDO_END
67 #define PSEUDO_END(name) \
68 SYSCALL_ERROR_HANDLER; \
69 END (name)
71 #undef PSEUDO_NOERRNO
72 #define PSEUDO_NOERRNO(name, syscall_name, args) \
73 .text; \
74 ENTRY (name) \
75 DO_CALL (syscall_name, args)
77 #undef PSEUDO_END_NOERRNO
78 #define PSEUDO_END_NOERRNO(name) \
79 END (name)
81 #define ret_NOERRNO rts
83 /* The function has to return the error code. */
84 #undef PSEUDO_ERRVAL
85 #define PSEUDO_ERRVAL(name, syscall_name, args) \
86 .text; \
87 ENTRY (name) \
88 DO_CALL (syscall_name, args); \
89 negl %d0
91 #undef PSEUDO_END_ERRVAL
92 #define PSEUDO_END_ERRVAL(name) \
93 END (name)
95 #define ret_ERRVAL rts
97 #ifdef PIC
98 # if RTLD_PRIVATE_ERRNO
99 # define SYSCALL_ERROR_HANDLER \
100 SYSCALL_ERROR_LABEL: \
101 lea (rtld_errno, %pc), %a0; \
102 neg.l %d0; \
103 move.l %d0, (%a0); \
104 move.l &-1, %d0; \
105 /* Copy return value to %a0 for syscalls that are declared to return \
106 a pointer (e.g., mmap). */ \
107 move.l %d0, %a0; \
108 rts;
109 # else /* !RTLD_PRIVATE_ERRNO */
110 /* Store (- %d0) into errno through the GOT. */
111 # if defined _LIBC_REENTRANT
112 # define SYSCALL_ERROR_HANDLER \
113 SYSCALL_ERROR_LABEL: \
114 neg.l %d0; \
115 move.l %d0, -(%sp); \
116 jbsr __errno_location@PLTPC; \
117 move.l (%sp)+, (%a0); \
118 move.l &-1, %d0; \
119 /* Copy return value to %a0 for syscalls that are declared to return \
120 a pointer (e.g., mmap). */ \
121 move.l %d0, %a0; \
122 rts;
123 # else /* !_LIBC_REENTRANT */
124 # define SYSCALL_ERROR_HANDLER \
125 SYSCALL_ERROR_LABEL: \
126 move.l (errno@GOTPC, %pc), %a0; \
127 neg.l %d0; \
128 move.l %d0, (%a0); \
129 move.l &-1, %d0; \
130 /* Copy return value to %a0 for syscalls that are declared to return \
131 a pointer (e.g., mmap). */ \
132 move.l %d0, %a0; \
133 rts;
134 # endif /* _LIBC_REENTRANT */
135 # endif /* RTLD_PRIVATE_ERRNO */
136 #else
137 # define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
138 #endif /* PIC */
140 /* Linux takes system call arguments in registers:
142 syscall number %d0 call-clobbered
143 arg 1 %d1 call-clobbered
144 arg 2 %d2 call-saved
145 arg 3 %d3 call-saved
146 arg 4 %d4 call-saved
147 arg 5 %d5 call-saved
149 The stack layout upon entering the function is:
151 20(%sp) Arg# 5
152 16(%sp) Arg# 4
153 12(%sp) Arg# 3
154 8(%sp) Arg# 2
155 4(%sp) Arg# 1
156 (%sp) Return address
158 (Of course a function with say 3 arguments does not have entries for
159 arguments 4 and 5.)
161 Separate move's are faster than movem, but need more space. Since
162 speed is more important, we don't use movem. Since %a0 and %a1 are
163 scratch registers, we can use them for saving as well. */
165 #define DO_CALL(syscall_name, args) \
166 move.l &SYS_ify(syscall_name), %d0; \
167 DOARGS_##args \
168 trap &0; \
169 UNDOARGS_##args
171 #define DOARGS_0 /* No arguments to frob. */
172 #define UNDOARGS_0 /* No arguments to unfrob. */
173 #define _DOARGS_0(n) /* No arguments to frob. */
175 #define DOARGS_1 _DOARGS_1 (4)
176 #define _DOARGS_1(n) move.l n(%sp), %d1; _DOARGS_0 (n)
177 #define UNDOARGS_1 UNDOARGS_0
179 #define DOARGS_2 _DOARGS_2 (8)
180 #define _DOARGS_2(n) move.l %d2, %a0; move.l n(%sp), %d2; _DOARGS_1 (n-4)
181 #define UNDOARGS_2 UNDOARGS_1; move.l %a0, %d2
183 #define DOARGS_3 _DOARGS_3 (12)
184 #define _DOARGS_3(n) move.l %d3, %a1; move.l n(%sp), %d3; _DOARGS_2 (n-4)
185 #define UNDOARGS_3 UNDOARGS_2; move.l %a1, %d3
187 #define DOARGS_4 _DOARGS_4 (16)
188 #define _DOARGS_4(n) move.l %d4, -(%sp); move.l n+4(%sp), %d4; _DOARGS_3 (n)
189 #define UNDOARGS_4 UNDOARGS_3; move.l (%sp)+, %d4
191 #define DOARGS_5 _DOARGS_5 (20)
192 #define _DOARGS_5(n) move.l %d5, -(%sp); move.l n+4(%sp), %d5; _DOARGS_4 (n)
193 #define UNDOARGS_5 UNDOARGS_4; move.l (%sp)+, %d5
196 #define ret rts
197 #if 0 /* Not used by Linux */
198 #define r0 %d0
199 #define r1 %d1
200 #define MOVE(x,y) movel x , y
201 #endif
203 #else /* not __ASSEMBLER__ */
205 /* Define a macro which expands into the inline wrapper code for a system
206 call. */
207 #undef INLINE_SYSCALL
208 #define INLINE_SYSCALL(name, nr, args...) \
209 ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args); \
210 if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0))\
212 __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \
213 _sys_result = (unsigned int) -1; \
215 (int) _sys_result; })
217 #undef INTERNAL_SYSCALL_DECL
218 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
220 /* Define a macro which expands inline into the wrapper code for a system
221 call. This use is for internal calls that do not need to handle errors
222 normally. It will never touch errno. This returns just what the kernel
223 gave back. */
224 #undef INTERNAL_SYSCALL
225 #define INTERNAL_SYSCALL(name, err, nr, args...) \
226 ({ unsigned int _sys_result; \
228 /* Load argument values in temporary variables
229 to perform side effects like function calls
230 before the call used registers are set. */ \
231 LOAD_ARGS_##nr (args) \
232 LOAD_REGS_##nr \
233 register int _d0 asm ("%d0") = __NR_##name; \
234 asm volatile ("trap #0" \
235 : "=d" (_d0) \
236 : "0" (_d0) ASM_ARGS_##nr \
237 : "memory"); \
238 _sys_result = _d0; \
240 (int) _sys_result; })
242 #undef INTERNAL_SYSCALL_ERROR_P
243 #define INTERNAL_SYSCALL_ERROR_P(val, err) \
244 ((unsigned int) (val) >= -4095U)
246 #undef INTERNAL_SYSCALL_ERRNO
247 #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
249 #define LOAD_ARGS_0()
250 #define LOAD_REGS_0
251 #define ASM_ARGS_0
252 #define LOAD_ARGS_1(a1) \
253 LOAD_ARGS_0 () \
254 int __arg1 = (int) (a1);
255 #define LOAD_REGS_1 \
256 register int _d1 asm ("d1") = __arg1; \
257 LOAD_REGS_0
258 #define ASM_ARGS_1 ASM_ARGS_0, "d" (_d1)
259 #define LOAD_ARGS_2(a1, a2) \
260 LOAD_ARGS_1 (a1) \
261 int __arg2 = (int) (a2);
262 #define LOAD_REGS_2 \
263 register int _d2 asm ("d2") = __arg2; \
264 LOAD_REGS_1
265 #define ASM_ARGS_2 ASM_ARGS_1, "d" (_d2)
266 #define LOAD_ARGS_3(a1, a2, a3) \
267 LOAD_ARGS_2 (a1, a2) \
268 int __arg3 = (int) (a3);
269 #define LOAD_REGS_3 \
270 register int _d3 asm ("d3") = __arg3; \
271 LOAD_REGS_2
272 #define ASM_ARGS_3 ASM_ARGS_2, "d" (_d3)
273 #define LOAD_ARGS_4(a1, a2, a3, a4) \
274 LOAD_ARGS_3 (a1, a2, a3) \
275 int __arg4 = (int) (a4);
276 #define LOAD_REGS_4 \
277 register int _d4 asm ("d4") = __arg4; \
278 LOAD_REGS_3
279 #define ASM_ARGS_4 ASM_ARGS_3, "d" (_d4)
280 #define LOAD_ARGS_5(a1, a2, a3, a4, a5) \
281 LOAD_ARGS_4 (a1, a2, a3, a4) \
282 int __arg5 = (int) (a5);
283 #define LOAD_REGS_5 \
284 register int _d5 asm ("d5") = __arg5; \
285 LOAD_REGS_4
286 #define ASM_ARGS_5 ASM_ARGS_4, "d" (_d5)
287 #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \
288 LOAD_ARGS_5 (a1, a2, a3, a4, a5) \
289 int __arg6 = (int) (a6);
290 #define LOAD_REGS_6 \
291 register int _a0 asm ("a0") = __arg6; \
292 LOAD_REGS_5
293 #define ASM_ARGS_6 ASM_ARGS_5, "a" (_a0)
295 #endif /* not __ASSEMBLER__ */