OSDN Git Service

Replace FSF snail mail address with URLs
[uclinux-h8/uClibc.git] / libc / sysdeps / linux / arm / sysdep.h
1 /* Assembler macros for ARM.
2    Copyright (C) 1997, 1998, 2003 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #ifndef _LINUX_ARM_SYSDEP_H
20 #define _LINUX_ARM_SYSDEP_H 1
21
22 #include <common/sysdep.h>
23 #include <bits/arm_asm.h>
24
25 #include <sys/syscall.h>
26 /* For Linux we can use the system call table in the header file
27         /usr/include/asm/unistd.h
28    of the kernel.  But these symbols do not follow the SYS_* syntax
29    so we have to redefine the `SYS_ify' macro here.  */
30 #undef SYS_ify
31 #define SWI_BASE  (0x900000)
32 #define SYS_ify(syscall_name)   (__NR_##syscall_name)
33
34 #ifdef  __ASSEMBLER__
35
36 /* Syntactic details of assembler.  */
37
38 #define ALIGNARG(log2) log2
39 /* For ELF we need the `.type' directive to make shared libs work right.  */
40 #define ASM_TYPE_DIRECTIVE(name,typearg) .type name,%##typearg;
41 #define ASM_SIZE_DIRECTIVE(name) .size name,.-name
42
43 /* In ELF C symbols are asm symbols.  */
44 #undef  NO_UNDERSCORES
45 #define NO_UNDERSCORES
46
47 #define PLTJMP(_x)      _x##(PLT)
48
49 /* APCS-32 doesn't preserve the condition codes across function call. */
50 #ifdef __APCS_32__
51 #define LOADREGS(cond, base, reglist...)\
52         ldm##cond       base,reglist
53 #ifdef __USE_BX__
54 #define RETINSTR(cond, reg)     \
55         bx##cond        reg
56 #define DO_RET(_reg)            \
57         bx _reg
58 #else
59 #define RETINSTR(cond, reg)     \
60         mov##cond       pc, reg
61 #define DO_RET(_reg)            \
62         mov pc, _reg
63 #endif
64 #else  /* APCS-26 */
65 #define LOADREGS(cond, base, reglist...)        \
66         ldm##cond       base,reglist^
67 #define RETINSTR(cond, reg)     \
68         mov##cond##s    pc, reg
69 #define DO_RET(_reg)            \
70         movs pc, _reg
71 #endif
72
73 /* Define an entry point visible from C.  */
74 #define ENTRY(name)                                             \
75   ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);                     \
76   ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function)             \
77   .align ALIGNARG(4);                                           \
78   name##:                                                       \
79   CALL_MCOUNT
80
81 #undef  END
82 #define END(name)                                               \
83   ASM_SIZE_DIRECTIVE(name)
84
85 /* If compiled for profiling, call `mcount' at the start of each function.  */
86 #ifdef  PROF
87 #define CALL_MCOUNT                     \
88         str     lr,[sp, #-4]!   ;       \
89         bl      PLTJMP(mcount)  ;       \
90         ldr     lr, [sp], #4    ;
91 #else
92 #define CALL_MCOUNT             /* Do nothing.  */
93 #endif
94
95 #ifdef  NO_UNDERSCORES
96 /* Since C identifiers are not normally prefixed with an underscore
97    on this system, the asm identifier `syscall_error' intrudes on the
98    C name space.  Make sure we use an innocuous name.  */
99 #define syscall_error   __syscall_error
100 #define mcount          _mcount
101 #endif
102 /* Linux uses a negative return value to indicate syscall errors,
103    unlike most Unices, which use the condition codes' carry flag.
104
105    Since version 2.1 the return value of a system call might be
106    negative even if the call succeeded.  E.g., the `lseek' system call
107    might return a large offset.  Therefore we must not anymore test
108    for < 0, but test for a real error by making sure the value in R0
109    is a real error number.  Linus said he will make sure the no syscall
110    returns a value in -1 .. -4095 as a valid result so we can safely
111    test with -4095.  */
112
113 #undef  PSEUDO
114 #define PSEUDO(name, syscall_name, args)                                \
115   .text;                                                                \
116   ENTRY (name);                                                         \
117     DO_CALL (syscall_name, args);                                       \
118     cmn r0, $4096;
119
120 #define PSEUDO_RET                                                      \
121     RETINSTR(cc, lr);                                                   \
122     b PLTJMP(SYSCALL_ERROR)
123 #undef ret
124 #define ret PSEUDO_RET
125
126 #undef  PSEUDO_END
127 #define PSEUDO_END(name)                                                \
128   SYSCALL_ERROR_HANDLER                                                 \
129   END (name)
130
131 #undef  PSEUDO_NOERRNO
132 #define PSEUDO_NOERRNO(name, syscall_name, args)                        \
133   .text;                                                                \
134   ENTRY (name);                                                         \
135     DO_CALL (syscall_name, args);
136
137 #define PSEUDO_RET_NOERRNO                                              \
138     DO_RET (lr);
139
140 #undef ret_NOERRNO
141 #define ret_NOERRNO PSEUDO_RET_NOERRNO
142
143 #undef  PSEUDO_END_NOERRNO
144 #define PSEUDO_END_NOERRNO(name)                                        \
145   END (name)
146
147 /* The function has to return the error code.  */
148 #undef  PSEUDO_ERRVAL
149 #define PSEUDO_ERRVAL(name, syscall_name, args) \
150   .text;                                                                \
151   ENTRY (name)                                                          \
152     DO_CALL (syscall_name, args);                                       \
153     rsb r0, r0, #0
154
155 #undef  PSEUDO_END_ERRVAL
156 #define PSEUDO_END_ERRVAL(name) \
157   END (name)
158
159 #define ret_ERRVAL PSEUDO_RET_NOERRNO
160
161 #if defined NOT_IN_libc
162 # define SYSCALL_ERROR __local_syscall_error
163 # ifdef RTLD_PRIVATE_ERRNO
164 #  define SYSCALL_ERROR_HANDLER                                 \
165 __local_syscall_error:                                          \
166        ldr     r1, 1f;                                          \
167        rsb     r0, r0, #0;                                      \
168 0:     str     r0, [pc, r1];                                    \
169        mvn     r0, #0;                                          \
170        DO_RET(lr);                                              \
171 1:     .word C_SYMBOL_NAME(rtld_errno) - 0b - 8;
172 # else
173 #  define SYSCALL_ERROR_HANDLER                                 \
174 __local_syscall_error:                                          \
175         str     lr, [sp, #-4]!;                                 \
176         str     r0, [sp, #-4]!;                                 \
177         bl      PLTJMP(C_SYMBOL_NAME(__errno_location));        \
178         ldr     r1, [sp], #4;                                   \
179         rsb     r1, r1, #0;                                     \
180         str     r1, [r0];                                       \
181         mvn     r0, #0;                                         \
182         ldr     pc, [sp], #4;
183 # endif
184 #else
185 # define SYSCALL_ERROR_HANDLER  /* Nothing here; code in sysdep.S is used.  */
186 # define SYSCALL_ERROR __syscall_error
187 #endif
188
189 /* Linux takes system call args in registers:
190         syscall number  in the SWI instruction
191         arg 1           r0
192         arg 2           r1
193         arg 3           r2
194         arg 4           r3
195         arg 5           r4      (this is different from the APCS convention)
196         arg 6           r5
197         arg 7           r6
198
199    The compiler is going to form a call by coming here, through PSEUDO, with
200    arguments
201         syscall number  in the DO_CALL macro
202         arg 1           r0
203         arg 2           r1
204         arg 3           r2
205         arg 4           r3
206         arg 5           [sp]
207         arg 6           [sp+4]
208         arg 7           [sp+8]
209
210    We need to shuffle values between R4..R6 and the stack so that the
211    caller's v1..v3 and stack frame are not corrupted, and the kernel
212    sees the right arguments.
213
214 */
215
216 #undef  DO_CALL
217 #if defined(__ARM_EABI__)
218 #define DO_CALL(syscall_name, args)             \
219     DOARGS_##args                               \
220     mov ip, r7;                                 \
221     ldr r7, =SYS_ify (syscall_name);            \
222     swi 0x0;                                    \
223     mov r7, ip;                                 \
224     UNDOARGS_##args
225 #else
226 #define DO_CALL(syscall_name, args)             \
227     DOARGS_##args                               \
228     swi SYS_ify (syscall_name);                 \
229     UNDOARGS_##args
230 #endif
231
232 #define DOARGS_0 /* nothing */
233 #define DOARGS_1 /* nothing */
234 #define DOARGS_2 /* nothing */
235 #define DOARGS_3 /* nothing */
236 #define DOARGS_4 /* nothing */
237 #define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4];
238 #define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5};
239 #define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6};
240
241 #define UNDOARGS_0 /* nothing */
242 #define UNDOARGS_1 /* nothing */
243 #define UNDOARGS_2 /* nothing */
244 #define UNDOARGS_3 /* nothing */
245 #define UNDOARGS_4 /* nothing */
246 #define UNDOARGS_5 ldr r4, [sp], $4;
247 #define UNDOARGS_6 ldmfd sp!, {r4, r5};
248 #define UNDOARGS_7 ldmfd sp!, {r4, r5, r6};
249
250 #else /* not __ASSEMBLER__ */
251 /* Define a macro which expands into the inline wrapper code for a system
252    call.  */
253 #undef INLINE_SYSCALL
254 #define INLINE_SYSCALL(name, nr, args...)                                       \
255   ({ unsigned int _inline_sys_result = INTERNAL_SYSCALL (name, , nr, args);     \
256      if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_inline_sys_result, ), 0)) \
257        {                                                                        \
258          __set_errno (INTERNAL_SYSCALL_ERRNO (_inline_sys_result, ));           \
259          _inline_sys_result = (unsigned int) -1;                                \
260        }                                                                        \
261      (int) _inline_sys_result; })
262
263 #undef INTERNAL_SYSCALL_DECL
264 #define INTERNAL_SYSCALL_DECL(err) do { } while (0)
265
266 #undef INTERNAL_SYSCALL_RAW
267 #if defined(__thumb__)
268 /* Hide the use of r7 from the compiler, this would be a lot
269  * easier but for the fact that the syscalls can exceed 255.
270  * For the moment the LOAD_ARG_7 is sacrificed.
271  * We can't use push/pop inside the asm because that breaks
272  * unwinding (ie. thread cancellation).
273  */
274 #define INTERNAL_SYSCALL_RAW(name, err, nr, args...)            \
275   ({ unsigned int _internal_sys_result;                         \
276     {                                                           \
277       int _sys_buf[2];                                          \
278       register int __a1 __asm__ ("a1");                         \
279       register int *_v3 __asm__ ("v3") = _sys_buf;              \
280       LOAD_ARGS_##nr (args)                                     \
281       *_v3 = (int) (name);                                      \
282       __asm__ __volatile__ ("str        r7, [v3, #4]\n"         \
283                     "\tldr      r7, [v3]\n"                     \
284                     "\tswi      0       @ syscall " #name "\n"  \
285                     "\tldr      r7, [v3, #4]"                   \
286                    : "=r" (__a1)                                \
287                     : "r" (_v3) ASM_ARGS_##nr                   \
288                     : "memory");                                \
289       _internal_sys_result = __a1;                              \
290     }                                                           \
291     (int) _internal_sys_result; })
292 #elif defined(__ARM_EABI__)
293 #define INTERNAL_SYSCALL_RAW(name, err, nr, args...)            \
294   ({unsigned int _internal_sys_result;                          \
295      {                                                          \
296        register int __a1 __asm__ ("r0"), _nr __asm__ ("r7");    \
297        LOAD_ARGS_##nr (args)                                    \
298        _nr = name;                                              \
299        __asm__ __volatile__ ("swi       0x0 @ syscall " #name   \
300                      : "=r" (__a1)                              \
301                      : "r" (_nr) ASM_ARGS_##nr                  \
302                      : "memory");                               \
303        _internal_sys_result = __a1;                             \
304      }                                                          \
305      (int) _internal_sys_result; })
306 #else /* !defined(__ARM_EABI__) */
307 #define INTERNAL_SYSCALL_RAW(name, err, nr, args...)            \
308   ({ unsigned int _internal_sys_result;                         \
309      {                                                          \
310        register int __a1 __asm__ ("a1");                        \
311        LOAD_ARGS_##nr (args)                                    \
312        __asm__ __volatile__ ("swi       %1 @ syscall " #name    \
313                      : "=r" (__a1)                              \
314                      : "i" (name) ASM_ARGS_##nr                 \
315                      : "memory");                               \
316        _internal_sys_result = __a1;                             \
317      }                                                          \
318      (int) _internal_sys_result; })
319 #endif
320
321 #undef INTERNAL_SYSCALL
322 #define INTERNAL_SYSCALL(name, err, nr, args...)                \
323         INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args)
324
325 #undef INTERNAL_SYSCALL_ARM
326 #define INTERNAL_SYSCALL_ARM(name, err, nr, args...)            \
327         INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args)
328
329 #undef INTERNAL_SYSCALL_ERROR_P
330 #define INTERNAL_SYSCALL_ERROR_P(val, err) \
331   ((unsigned int) (val) >= 0xfffff001u)
332
333 #undef INTERNAL_SYSCALL_ERRNO
334 #define INTERNAL_SYSCALL_ERRNO(val, err)        (-(val))
335
336 #if defined(__ARM_EABI__)
337 #undef INTERNAL_SYSCALL_NCS
338 #define INTERNAL_SYSCALL_NCS(number, err, nr, args...)          \
339         INTERNAL_SYSCALL_RAW(number, err, nr, args)
340 #else
341 /* We can't implement non-constant syscalls directly since the syscall
342    number is normally encoded in the instruction.  So use SYS_syscall.  */
343 #undef INTERNAL_SYSCALL_NCS
344 #define INTERNAL_SYSCALL_NCS(number, err, nr, args...)          \
345         INTERNAL_SYSCALL_NCS_##nr (number, err, args)
346
347 #define INTERNAL_SYSCALL_NCS_0(number, err, args...)            \
348         INTERNAL_SYSCALL (syscall, err, 1, number, args)
349 #define INTERNAL_SYSCALL_NCS_1(number, err, args...)            \
350         INTERNAL_SYSCALL (syscall, err, 2, number, args)
351 #define INTERNAL_SYSCALL_NCS_2(number, err, args...)            \
352         INTERNAL_SYSCALL (syscall, err, 3, number, args)
353 #define INTERNAL_SYSCALL_NCS_3(number, err, args...)            \
354         INTERNAL_SYSCALL (syscall, err, 4, number, args)
355 #define INTERNAL_SYSCALL_NCS_4(number, err, args...)            \
356         INTERNAL_SYSCALL (syscall, err, 5, number, args)
357 #define INTERNAL_SYSCALL_NCS_5(number, err, args...)            \
358         INTERNAL_SYSCALL (syscall, err, 6, number, args)
359 #endif
360
361 #endif  /* __ASSEMBLER__ */
362
363 /* Pointer mangling is not yet supported for ARM.  */
364 #define PTR_MANGLE(var) (void) (var)
365 #define PTR_DEMANGLE(var) (void) (var)
366
367 #endif /* linux/arm/sysdep.h */