(INTERNAL_SYSCALL, INTERNAL_SYSCALL_ERROR_P, INTERNAL_SYSCALL_ERRNO):
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / m68k / sysdep.h
1 /* Copyright (C) 1996, 1997, 1998, 2000, 2003 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.
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 #include <sysdeps/unix/sysdep.h>
22 #include <sysdeps/m68k/sysdep.h>
23
24 /* Defines RTLD_PRIVATE_ERRNO.  */
25 #include <dl-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 #ifdef __ASSEMBLER__
39
40 /* Linux uses a negative return value to indicate syscall errors, unlike
41    most Unices, which use the condition codes' carry flag.
42
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.  */
49
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
57
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
65
66 #undef PSEUDO_END
67 #define PSEUDO_END(name)                                                      \
68   SYSCALL_ERROR_HANDLER;                                                      \
69   END (name)
70
71 #ifdef PIC
72 # if RTLD_PRIVATE_ERRNO
73 #  define SYSCALL_ERROR_HANDLER                                               \
74 SYSCALL_ERROR_LABEL:                                                          \
75     lea (errno, %pc), %a0;                                                    \
76     neg.l %d0;                                                                \
77     move.l %d0, (%a0);                                                        \
78     move.l &-1, %d0;                                                          \
79     /* Copy return value to %a0 for syscalls that are declared to return      \
80        a pointer (e.g., mmap).  */                                            \
81     move.l %d0, %a0;                                                          \
82     rts;
83 # else /* !RTLD_PRIVATE_ERRNO */
84 /* Store (- %d0) into errno through the GOT.  */
85 #  if defined _LIBC_REENTRANT
86 #   define SYSCALL_ERROR_HANDLER                                              \
87 SYSCALL_ERROR_LABEL:                                                          \
88     neg.l %d0;                                                                \
89     move.l %d0, -(%sp);                                                       \
90     jbsr __errno_location@PLTPC;                                              \
91     move.l (%sp)+, (%a0);                                                     \
92     move.l &-1, %d0;                                                          \
93     /* Copy return value to %a0 for syscalls that are declared to return      \
94        a pointer (e.g., mmap).  */                                            \
95     move.l %d0, %a0;                                                          \
96     rts;
97 #  else /* !_LIBC_REENTRANT */
98 #   define SYSCALL_ERROR_HANDLER                                              \
99 SYSCALL_ERROR_LABEL:                                                          \
100     move.l (errno@GOTPC, %pc), %a0;                                           \
101     neg.l %d0;                                                                \
102     move.l %d0, (%a0);                                                        \
103     move.l &-1, %d0;                                                          \
104     /* Copy return value to %a0 for syscalls that are declared to return      \
105        a pointer (e.g., mmap).  */                                            \
106     move.l %d0, %a0;                                                          \
107     rts;
108 #  endif /* _LIBC_REENTRANT */
109 # endif /* RTLD_PRIVATE_ERRNO */
110 #else
111 # define SYSCALL_ERROR_HANDLER  /* Nothing here; code in sysdep.S is used.  */
112 #endif /* PIC */
113
114 /* Linux takes system call arguments in registers:
115
116         syscall number  %d0          call-clobbered
117         arg 1           %d1          call-clobbered
118         arg 2           %d2          call-saved
119         arg 3           %d3          call-saved
120         arg 4           %d4          call-saved
121         arg 5           %d5          call-saved
122
123    The stack layout upon entering the function is:
124
125         20(%sp)         Arg# 5
126         16(%sp)         Arg# 4
127         12(%sp)         Arg# 3
128          8(%sp)         Arg# 2
129          4(%sp)         Arg# 1
130           (%sp)         Return address
131
132    (Of course a function with say 3 arguments does not have entries for
133    arguments 4 and 5.)
134
135    Separate move's are faster than movem, but need more space.  Since
136    speed is more important, we don't use movem.  Since %a0 and %a1 are
137    scratch registers, we can use them for saving as well.  */
138
139 #define DO_CALL(syscall_name, args)                                           \
140     move.l &SYS_ify(syscall_name), %d0;                                       \
141     DOARGS_##args                                                             \
142     trap &0;                                                                  \
143     UNDOARGS_##args
144
145 #define DOARGS_0        /* No arguments to frob.  */
146 #define UNDOARGS_0      /* No arguments to unfrob.  */
147 #define _DOARGS_0(n)    /* No arguments to frob.  */
148
149 #define DOARGS_1        _DOARGS_1 (4)
150 #define _DOARGS_1(n)    move.l n(%sp), %d1; _DOARGS_0 (n)
151 #define UNDOARGS_1      UNDOARGS_0
152
153 #define DOARGS_2        _DOARGS_2 (8)
154 #define _DOARGS_2(n)    move.l %d2, %a0; move.l n(%sp), %d2; _DOARGS_1 (n-4)
155 #define UNDOARGS_2      UNDOARGS_1; move.l %a0, %d2
156
157 #define DOARGS_3        _DOARGS_3 (12)
158 #define _DOARGS_3(n)    move.l %d3, %a1; move.l n(%sp), %d3; _DOARGS_2 (n-4)
159 #define UNDOARGS_3      UNDOARGS_2; move.l %a1, %d3
160
161 #define DOARGS_4        _DOARGS_4 (16)
162 #define _DOARGS_4(n)    move.l %d4, -(%sp); move.l n+4(%sp), %d4; _DOARGS_3 (n)
163 #define UNDOARGS_4      UNDOARGS_3; move.l (%sp)+, %d4
164
165 #define DOARGS_5        _DOARGS_5 (20)
166 #define _DOARGS_5(n)    move.l %d5, -(%sp); move.l n+4(%sp), %d5; _DOARGS_4 (n)
167 #define UNDOARGS_5      UNDOARGS_4; move.l (%sp)+, %d5
168
169
170 #define ret     rts
171 #if 0 /* Not used by Linux */
172 #define r0      %d0
173 #define r1      %d1
174 #define MOVE(x,y)       movel x , y
175 #endif
176
177 #else /* not __ASSEMBLER__ */
178
179 /* Define a macro which expands into the inline wrapper code for a system
180    call.  */
181 #undef INLINE_SYSCALL
182 #define INLINE_SYSCALL(name, nr, args...)                               \
183   ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args);    \
184      if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0))\
185        {                                                                \
186          __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, ));          \
187          _sys_result = (unsigned int) -1;                               \
188        }                                                                \
189      (int) _sys_result; })
190
191 #undef INTERNAL_SYSCALL_DECL
192 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
193
194 /* Define a macro which expands inline into the wrapper code for a system
195    call.  This use is for internal calls that do not need to handle errors
196    normally.  It will never touch errno.  This returns just what the kernel
197    gave back.  */
198 #undef INTERNAL_SYSCALL
199 #define INTERNAL_SYSCALL(name, err, nr, args...)        \
200   ({ unsigned int _sys_result;                          \
201      {                                                  \
202        LOAD_ARGS_##nr (args)                            \
203        register int _d0 asm ("%d0") = __NR_##name;      \
204        asm volatile ("trap #0"                          \
205                      : "=d" (_d0)                       \
206                      : "0" (_d0) ASM_ARGS_##nr          \
207                      : "memory");                       \
208        _sys_result = _d0;                               \
209      }                                                  \
210      (int) _sys_result; })
211
212 #undef INTERNAL_SYSCALL_ERROR_P
213 #define INTERNAL_SYSCALL_ERROR_P(val, err)              \
214   ((unsigned int) (val) >= -4095U)
215
216 #undef INTERNAL_SYSCALL_ERRNO
217 #define INTERNAL_SYSCALL_ERRNO(val, err)        (-(val))
218
219 #define LOAD_ARGS_0()
220 #define ASM_ARGS_0
221 #define LOAD_ARGS_1(a1)                         \
222   register int _d1 asm ("d1") = (int) (a1);     \
223   LOAD_ARGS_0 ()
224 #define ASM_ARGS_1      ASM_ARGS_0, "d" (_d1)
225 #define LOAD_ARGS_2(a1, a2)                     \
226   register int _d2 asm ("d2") = (int) (a2);     \
227   LOAD_ARGS_1 (a1)
228 #define ASM_ARGS_2      ASM_ARGS_1, "d" (_d2)
229 #define LOAD_ARGS_3(a1, a2, a3)                 \
230   register int _d3 asm ("d3") = (int) (a3);     \
231   LOAD_ARGS_2 (a1, a2)
232 #define ASM_ARGS_3      ASM_ARGS_2, "d" (_d3)
233 #define LOAD_ARGS_4(a1, a2, a3, a4)             \
234   register int _d4 asm ("d4") = (int) (a4);     \
235   LOAD_ARGS_3 (a1, a2, a3)
236 #define ASM_ARGS_4      ASM_ARGS_3, "d" (_d4)
237 #define LOAD_ARGS_5(a1, a2, a3, a4, a5)         \
238   register int _d5 asm ("d5") = (int) (a5);     \
239   LOAD_ARGS_4 (a1, a2, a3, a4)
240 #define ASM_ARGS_5      ASM_ARGS_4, "d" (_d5)
241 #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6)     \
242   register int _a0 asm ("a0") = (int) (a6);     \
243   LOAD_ARGS_5 (a1, a2, a3, a4, a5)
244 #define ASM_ARGS_6      ASM_ARGS_5, "a" (_a0)
245
246 #endif /* not __ASSEMBLER__ */