]>
Commit | Line | Data |
---|---|---|
aeeec7fb | 1 | /* Copyright (C) 1992, 93, 1995-2000, 2002, 2003 Free Software Foundation, Inc. |
c751295f UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995. | |
4 | ARM changes by Philip Blundell, <pjb27@cam.ac.uk>, May 1997. | |
8d2485ed | 5 | |
c751295f | 6 | The GNU C Library is free software; you can redistribute it and/or |
3214b89b AJ |
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. | |
8d2485ed | 10 | |
c751295f UD |
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 | |
3214b89b | 14 | Lesser General Public License for more details. |
8d2485ed | 15 | |
3214b89b AJ |
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. */ | |
8d2485ed UD |
20 | |
21 | #ifndef _LINUX_ARM_SYSDEP_H | |
22 | #define _LINUX_ARM_SYSDEP_H 1 | |
23 | ||
24 | /* There is some commonality. */ | |
25 | #include <sysdeps/unix/arm/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 | |
d2099b0d UD |
32 | #define SWI_BASE (0x900000) |
33 | #define SYS_ify(syscall_name) (__NR_##syscall_name) | |
8d2485ed UD |
34 | |
35 | ||
e0ebc3b2 | 36 | #ifdef __ASSEMBLER__ |
8d2485ed UD |
37 | |
38 | /* Linux uses a negative return value to indicate syscall errors, | |
39 | unlike most Unices, which use the condition codes' carry flag. | |
40 | ||
41 | Since version 2.1 the return value of a system call might be | |
42 | negative even if the call succeeded. E.g., the `lseek' system call | |
43 | might return a large offset. Therefore we must not anymore test | |
0f2a261a | 44 | for < 0, but test for a real error by making sure the value in R0 |
8d2485ed UD |
45 | is a real error number. Linus said he will make sure the no syscall |
46 | returns a value in -1 .. -4095 as a valid result so we can savely | |
47 | test with -4095. */ | |
ff550b1f | 48 | |
8d2485ed UD |
49 | #undef PSEUDO |
50 | #define PSEUDO(name, syscall_name, args) \ | |
51 | .text; \ | |
86ffa1b4 | 52 | ENTRY (name); \ |
631d94cb | 53 | DO_CALL (syscall_name, args); \ |
63ac74aa UD |
54 | cmn r0, $4096; |
55 | ||
56 | #define PSEUDO_RET \ | |
57 | RETINSTR(movcc, pc, lr); \ | |
2f0910ca | 58 | b PLTJMP(SYSCALL_ERROR) |
63ac74aa UD |
59 | #undef ret |
60 | #define ret PSEUDO_RET | |
8d2485ed UD |
61 | |
62 | #undef PSEUDO_END | |
63 | #define PSEUDO_END(name) \ | |
64 | SYSCALL_ERROR_HANDLER \ | |
65 | END (name) | |
66 | ||
98f7320f UD |
67 | #undef PSEUDO_NOERRNO |
68 | #define PSEUDO_NOERRNO(name, syscall_name, args) \ | |
69 | .text; \ | |
70 | ENTRY (name); \ | |
71 | DO_CALL (syscall_name, args); | |
72 | ||
73 | #define PSEUDO_RET_NOERRNO \ | |
44acff5d RM |
74 | RETINSTR(mov, pc, lr); |
75 | ||
98f7320f UD |
76 | #undef ret_NOERRNO |
77 | #define ret_NOERRNO PSEUDO_RET_NOERRNO | |
78 | ||
79 | #undef PSEUDO_END_NOERRNO | |
80 | #define PSEUDO_END_NOERRNO(name) \ | |
81 | END (name) | |
82 | ||
ae53e7a7 UD |
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 | rsb r0, r0, #0 | |
90 | ||
91 | #undef PSEUDO_END_ERRVAL | |
92 | #define PSEUDO_END_ERRVAL(name) \ | |
93 | END (name) | |
94 | ||
95 | #define ret_ERRVAL PSEUDO_RET_NOERRNO | |
96 | ||
2f0910ca UD |
97 | #if NOT_IN_libc |
98 | # define SYSCALL_ERROR __local_syscall_error | |
99 | # define SYSCALL_ERROR_HANDLER \ | |
100 | __local_syscall_error: \ | |
101 | str lr, [sp, #-4]!; \ | |
102 | str r0, [sp, #-4]!; \ | |
103 | bl PLTJMP(C_SYMBOL_NAME(__errno_location)); \ | |
104 | ldr r1, [sp], #4; \ | |
105 | rsb r1, r1, #0; \ | |
106 | str r1, [r0]; \ | |
107 | mvn r0, #0; \ | |
108 | ldr pc, [sp], #4; | |
109 | #else | |
110 | # define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ | |
111 | # define SYSCALL_ERROR __syscall_error | |
112 | #endif | |
ff550b1f UD |
113 | |
114 | /* Linux takes system call args in registers: | |
115 | syscall number in the SWI instruction | |
116 | arg 1 r0 | |
117 | arg 2 r1 | |
118 | arg 3 r2 | |
119 | arg 4 r3 | |
120 | arg 5 r4 (this is different from the APCS convention) | |
62749187 UD |
121 | arg 6 r5 |
122 | arg 7 r6 | |
ff550b1f UD |
123 | |
124 | The compiler is going to form a call by coming here, through PSEUDO, with | |
125 | arguments | |
126 | syscall number in the DO_CALL macro | |
127 | arg 1 r0 | |
128 | arg 2 r1 | |
129 | arg 3 r2 | |
130 | arg 4 r3 | |
131 | arg 5 [sp] | |
62749187 UD |
132 | arg 6 [sp+4] |
133 | arg 7 [sp+8] | |
ff550b1f | 134 | |
62749187 UD |
135 | We need to shuffle values between R4..R6 and the stack so that the |
136 | caller's v1..v3 and stack frame are not corrupted, and the kernel | |
137 | sees the right arguments. | |
ff550b1f UD |
138 | |
139 | */ | |
8d2485ed UD |
140 | |
141 | #undef DO_CALL | |
631d94cb | 142 | #define DO_CALL(syscall_name, args) \ |
ff550b1f UD |
143 | DOARGS_##args \ |
144 | swi SYS_ify (syscall_name); \ | |
145 | UNDOARGS_##args | |
146 | ||
147 | #define DOARGS_0 /* nothing */ | |
148 | #define DOARGS_1 /* nothing */ | |
149 | #define DOARGS_2 /* nothing */ | |
150 | #define DOARGS_3 /* nothing */ | |
151 | #define DOARGS_4 /* nothing */ | |
62749187 UD |
152 | #define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4]; |
153 | #define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5}; | |
154 | #define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6}; | |
ff550b1f UD |
155 | |
156 | #define UNDOARGS_0 /* nothing */ | |
157 | #define UNDOARGS_1 /* nothing */ | |
158 | #define UNDOARGS_2 /* nothing */ | |
159 | #define UNDOARGS_3 /* nothing */ | |
160 | #define UNDOARGS_4 /* nothing */ | |
13270773 | 161 | #define UNDOARGS_5 ldr r4, [sp], $4; |
62749187 UD |
162 | #define UNDOARGS_6 ldmfd sp!, {r4, r5}; |
163 | #define UNDOARGS_7 ldmfd sp!, {r4, r5, r6}; | |
8d2485ed | 164 | |
ba023f01 UD |
165 | #else /* not __ASSEMBLER__ */ |
166 | ||
167 | /* Define a macro which expands into the inline wrapper code for a system | |
168 | call. */ | |
169 | #undef INLINE_SYSCALL | |
2f0910ca | 170 | #define INLINE_SYSCALL(name, nr, args...) \ |
114e7d50 UD |
171 | ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args); \ |
172 | if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0)) \ | |
2f0910ca | 173 | { \ |
114e7d50 | 174 | __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \ |
2f0910ca UD |
175 | _sys_result = (unsigned int) -1; \ |
176 | } \ | |
177 | (int) _sys_result; }) | |
178 | ||
aeeec7fb UD |
179 | #undef INTERNAL_SYSCALL_DECL |
180 | #define INTERNAL_SYSCALL_DECL(err) do { } while (0) | |
181 | ||
2f0910ca | 182 | #undef INTERNAL_SYSCALL |
aeeec7fb | 183 | #define INTERNAL_SYSCALL(name, err, nr, args...) \ |
ba023f01 UD |
184 | ({ unsigned int _sys_result; \ |
185 | { \ | |
186 | register int _a1 asm ("a1"); \ | |
187 | LOAD_ARGS_##nr (args) \ | |
a9b40c2a | 188 | asm volatile ("swi %1 @ syscall " #name \ |
ba023f01 UD |
189 | : "=r" (_a1) \ |
190 | : "i" (SYS_ify(name)) ASM_ARGS_##nr \ | |
cf666e4b | 191 | : "memory"); \ |
ba023f01 UD |
192 | _sys_result = _a1; \ |
193 | } \ | |
ba023f01 UD |
194 | (int) _sys_result; }) |
195 | ||
2f0910ca | 196 | #undef INTERNAL_SYSCALL_ERROR_P |
aeeec7fb UD |
197 | #define INTERNAL_SYSCALL_ERROR_P(val, err) \ |
198 | ((unsigned int) (val) >= 0xfffff001u) | |
2f0910ca UD |
199 | |
200 | #undef INTERNAL_SYSCALL_ERRNO | |
aeeec7fb | 201 | #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) |
2f0910ca | 202 | |
ba023f01 UD |
203 | #define LOAD_ARGS_0() |
204 | #define ASM_ARGS_0 | |
205 | #define LOAD_ARGS_1(a1) \ | |
206 | _a1 = (int) (a1); \ | |
207 | LOAD_ARGS_0 () | |
208 | #define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1) | |
209 | #define LOAD_ARGS_2(a1, a2) \ | |
210 | register int _a2 asm ("a2") = (int) (a2); \ | |
211 | LOAD_ARGS_1 (a1) | |
212 | #define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2) | |
213 | #define LOAD_ARGS_3(a1, a2, a3) \ | |
214 | register int _a3 asm ("a3") = (int) (a3); \ | |
215 | LOAD_ARGS_2 (a1, a2) | |
216 | #define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3) | |
217 | #define LOAD_ARGS_4(a1, a2, a3, a4) \ | |
218 | register int _a4 asm ("a4") = (int) (a4); \ | |
219 | LOAD_ARGS_3 (a1, a2, a3) | |
220 | #define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4) | |
221 | #define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ | |
222 | register int _v1 asm ("v1") = (int) (a5); \ | |
223 | LOAD_ARGS_4 (a1, a2, a3, a4) | |
224 | #define ASM_ARGS_5 ASM_ARGS_4, "r" (_v1) | |
62749187 UD |
225 | #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \ |
226 | register int _v2 asm ("v2") = (int) (a6); \ | |
227 | LOAD_ARGS_5 (a1, a2, a3, a4, a5) | |
228 | #define ASM_ARGS_6 ASM_ARGS_5, "r" (_v2) | |
229 | #define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7) \ | |
230 | register int _v3 asm ("v3") = (int) (a7); \ | |
231 | LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6) | |
232 | #define ASM_ARGS_7 ASM_ARGS_6, "r" (_v3) | |
ba023f01 | 233 | |
e0ebc3b2 | 234 | #endif /* __ASSEMBLER__ */ |
8d2485ed UD |
235 | |
236 | #endif /* linux/arm/sysdep.h */ |