]>
Commit | Line | Data |
---|---|---|
6aca81bb | 1 | /* Copyright (C) 1992, 93, 1995-2000, 2002, 2003 Free Software Foundation, Inc. |
bfbc5754 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. | |
1f205a47 | 5 | |
bfbc5754 | 6 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 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. | |
1f205a47 | 10 | |
bfbc5754 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 | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
1f205a47 | 15 | |
41bdb6e2 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. */ | |
1f205a47 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 | |
fe0ec73e UD |
32 | #define SWI_BASE (0x900000) |
33 | #define SYS_ify(syscall_name) (__NR_##syscall_name) | |
1f205a47 UD |
34 | |
35 | ||
66715f83 | 36 | #ifdef __ASSEMBLER__ |
1f205a47 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 | |
31161268 | 44 | for < 0, but test for a real error by making sure the value in R0 |
1f205a47 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. */ | |
652e8a1e | 48 | |
1f205a47 UD |
49 | #undef PSEUDO |
50 | #define PSEUDO(name, syscall_name, args) \ | |
51 | .text; \ | |
28c9c2c4 | 52 | ENTRY (name); \ |
ffa8d2a0 | 53 | DO_CALL (syscall_name, args); \ |
497b8ef4 UD |
54 | cmn r0, $4096; |
55 | ||
56 | #define PSEUDO_RET \ | |
57 | RETINSTR(movcc, pc, lr); \ | |
b5facfda | 58 | b PLTJMP(SYSCALL_ERROR) |
497b8ef4 UD |
59 | #undef ret |
60 | #define ret PSEUDO_RET | |
1f205a47 UD |
61 | |
62 | #undef PSEUDO_END | |
63 | #define PSEUDO_END(name) \ | |
64 | SYSCALL_ERROR_HANDLER \ | |
65 | END (name) | |
66 | ||
9eb88290 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 \ | |
312472fc RM |
74 | RETINSTR(mov, pc, lr); |
75 | ||
9eb88290 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 | ||
b5facfda UD |
83 | #if NOT_IN_libc |
84 | # define SYSCALL_ERROR __local_syscall_error | |
85 | # define SYSCALL_ERROR_HANDLER \ | |
86 | __local_syscall_error: \ | |
87 | str lr, [sp, #-4]!; \ | |
88 | str r0, [sp, #-4]!; \ | |
89 | bl PLTJMP(C_SYMBOL_NAME(__errno_location)); \ | |
90 | ldr r1, [sp], #4; \ | |
91 | rsb r1, r1, #0; \ | |
92 | str r1, [r0]; \ | |
93 | mvn r0, #0; \ | |
94 | ldr pc, [sp], #4; | |
95 | #else | |
96 | # define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ | |
97 | # define SYSCALL_ERROR __syscall_error | |
98 | #endif | |
652e8a1e UD |
99 | |
100 | /* Linux takes system call args in registers: | |
101 | syscall number in the SWI instruction | |
102 | arg 1 r0 | |
103 | arg 2 r1 | |
104 | arg 3 r2 | |
105 | arg 4 r3 | |
106 | arg 5 r4 (this is different from the APCS convention) | |
010d7766 UD |
107 | arg 6 r5 |
108 | arg 7 r6 | |
652e8a1e UD |
109 | |
110 | The compiler is going to form a call by coming here, through PSEUDO, with | |
111 | arguments | |
112 | syscall number in the DO_CALL macro | |
113 | arg 1 r0 | |
114 | arg 2 r1 | |
115 | arg 3 r2 | |
116 | arg 4 r3 | |
117 | arg 5 [sp] | |
010d7766 UD |
118 | arg 6 [sp+4] |
119 | arg 7 [sp+8] | |
652e8a1e | 120 | |
010d7766 UD |
121 | We need to shuffle values between R4..R6 and the stack so that the |
122 | caller's v1..v3 and stack frame are not corrupted, and the kernel | |
123 | sees the right arguments. | |
652e8a1e UD |
124 | |
125 | */ | |
1f205a47 UD |
126 | |
127 | #undef DO_CALL | |
ffa8d2a0 | 128 | #define DO_CALL(syscall_name, args) \ |
652e8a1e UD |
129 | DOARGS_##args \ |
130 | swi SYS_ify (syscall_name); \ | |
131 | UNDOARGS_##args | |
132 | ||
133 | #define DOARGS_0 /* nothing */ | |
134 | #define DOARGS_1 /* nothing */ | |
135 | #define DOARGS_2 /* nothing */ | |
136 | #define DOARGS_3 /* nothing */ | |
137 | #define DOARGS_4 /* nothing */ | |
010d7766 UD |
138 | #define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4]; |
139 | #define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5}; | |
140 | #define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6}; | |
652e8a1e UD |
141 | |
142 | #define UNDOARGS_0 /* nothing */ | |
143 | #define UNDOARGS_1 /* nothing */ | |
144 | #define UNDOARGS_2 /* nothing */ | |
145 | #define UNDOARGS_3 /* nothing */ | |
146 | #define UNDOARGS_4 /* nothing */ | |
7feefb69 | 147 | #define UNDOARGS_5 ldr r4, [sp], $4; |
010d7766 UD |
148 | #define UNDOARGS_6 ldmfd sp!, {r4, r5}; |
149 | #define UNDOARGS_7 ldmfd sp!, {r4, r5, r6}; | |
1f205a47 | 150 | |
edb570bb UD |
151 | #else /* not __ASSEMBLER__ */ |
152 | ||
153 | /* Define a macro which expands into the inline wrapper code for a system | |
154 | call. */ | |
155 | #undef INLINE_SYSCALL | |
b5facfda | 156 | #define INLINE_SYSCALL(name, nr, args...) \ |
44ed664b UD |
157 | ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args); \ |
158 | if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0)) \ | |
b5facfda | 159 | { \ |
44ed664b | 160 | __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \ |
b5facfda UD |
161 | _sys_result = (unsigned int) -1; \ |
162 | } \ | |
163 | (int) _sys_result; }) | |
164 | ||
6aca81bb UD |
165 | #undef INTERNAL_SYSCALL_DECL |
166 | #define INTERNAL_SYSCALL_DECL(err) do { } while (0) | |
167 | ||
b5facfda | 168 | #undef INTERNAL_SYSCALL |
6aca81bb | 169 | #define INTERNAL_SYSCALL(name, err, nr, args...) \ |
edb570bb UD |
170 | ({ unsigned int _sys_result; \ |
171 | { \ | |
172 | register int _a1 asm ("a1"); \ | |
173 | LOAD_ARGS_##nr (args) \ | |
a64e578b | 174 | asm volatile ("swi %1 @ syscall " #name \ |
edb570bb UD |
175 | : "=r" (_a1) \ |
176 | : "i" (SYS_ify(name)) ASM_ARGS_##nr \ | |
c6289757 | 177 | : "memory"); \ |
edb570bb UD |
178 | _sys_result = _a1; \ |
179 | } \ | |
edb570bb UD |
180 | (int) _sys_result; }) |
181 | ||
b5facfda | 182 | #undef INTERNAL_SYSCALL_ERROR_P |
6aca81bb UD |
183 | #define INTERNAL_SYSCALL_ERROR_P(val, err) \ |
184 | ((unsigned int) (val) >= 0xfffff001u) | |
b5facfda UD |
185 | |
186 | #undef INTERNAL_SYSCALL_ERRNO | |
6aca81bb | 187 | #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) |
b5facfda | 188 | |
edb570bb UD |
189 | #define LOAD_ARGS_0() |
190 | #define ASM_ARGS_0 | |
191 | #define LOAD_ARGS_1(a1) \ | |
192 | _a1 = (int) (a1); \ | |
193 | LOAD_ARGS_0 () | |
194 | #define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1) | |
195 | #define LOAD_ARGS_2(a1, a2) \ | |
196 | register int _a2 asm ("a2") = (int) (a2); \ | |
197 | LOAD_ARGS_1 (a1) | |
198 | #define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2) | |
199 | #define LOAD_ARGS_3(a1, a2, a3) \ | |
200 | register int _a3 asm ("a3") = (int) (a3); \ | |
201 | LOAD_ARGS_2 (a1, a2) | |
202 | #define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3) | |
203 | #define LOAD_ARGS_4(a1, a2, a3, a4) \ | |
204 | register int _a4 asm ("a4") = (int) (a4); \ | |
205 | LOAD_ARGS_3 (a1, a2, a3) | |
206 | #define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4) | |
207 | #define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ | |
208 | register int _v1 asm ("v1") = (int) (a5); \ | |
209 | LOAD_ARGS_4 (a1, a2, a3, a4) | |
210 | #define ASM_ARGS_5 ASM_ARGS_4, "r" (_v1) | |
010d7766 UD |
211 | #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \ |
212 | register int _v2 asm ("v2") = (int) (a6); \ | |
213 | LOAD_ARGS_5 (a1, a2, a3, a4, a5) | |
214 | #define ASM_ARGS_6 ASM_ARGS_5, "r" (_v2) | |
215 | #define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7) \ | |
216 | register int _v3 asm ("v3") = (int) (a7); \ | |
217 | LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6) | |
218 | #define ASM_ARGS_7 ASM_ARGS_6, "r" (_v3) | |
edb570bb | 219 | |
66715f83 | 220 | #endif /* __ASSEMBLER__ */ |
1f205a47 UD |
221 | |
222 | #endif /* linux/arm/sysdep.h */ |