]>
Commit | Line | Data |
---|---|---|
d115c0d8 AO |
1 | /* Copyright 2001, 2004 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. | |
3 | Contributed by Alexandre Oliva <aoliva@redhat.com>. | |
4 | Based on ../i386/sysdep.h. | |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
7 | modify it under the terms of the GNU Library General Public License as | |
8 | published by the Free Software Foundation; either version 2 of the | |
9 | 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 | Library General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Library General Public | |
ab84e3ff PE |
17 | License along with the GNU C Library. If not, see |
18 | <http://www.gnu.org/licenses/>. */ | |
d115c0d8 AO |
19 | |
20 | #ifndef _LINUX_AM33_SYSDEP_H | |
21 | #define _LINUX_AM33_SYSDEP_H 1 | |
22 | ||
23 | /* There is some commonality. */ | |
24 | #include "../../../am33/sysdep.h" | |
25 | ||
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 SYS_ify(syscall_name) __NR_##syscall_name | |
32 | ||
33 | /* ELF-like local names start with `.L'. */ | |
34 | #undef L | |
35 | #define L(name) .L##name | |
36 | ||
37 | #ifdef __ASSEMBLER__ | |
38 | ||
39 | /* Linux uses a negative return value to indicate syscall errors, | |
40 | unlike most Unices, which use the condition codes' carry flag. | |
41 | ||
42 | Since version 2.1 the return value of a system call might be | |
43 | negative even if the call succeeded. E.g., the `lseek' system call | |
44 | might return a large offset. Therefore we must not anymore test | |
45 | for < 0, but test for a real error by making sure the value in %eax | |
46 | is a real error number. Linus said he will make sure the no syscall | |
47 | returns a value in -1 .. -4095 as a valid result so we can savely | |
48 | test with -4095. */ | |
49 | ||
50 | /* We don't want the label for the error handle to be global when we define | |
51 | it here. */ | |
52 | #ifdef PIC | |
53 | # define SYSCALL_ERROR_LABEL 0f | |
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 -126,d0; \ | |
64 | bls L(pseudo_end); \ | |
65 | jmp SYSCALL_ERROR_LABEL; \ | |
66 | L(pseudo_end): \ | |
67 | mov d0,a0; | |
68 | ||
69 | #undef PSEUDO_END | |
70 | #define PSEUDO_END(name) \ | |
71 | SYSCALL_ERROR_HANDLER \ | |
72 | END (name) | |
73 | ||
74 | #undef PSEUDO_NOERROR | |
75 | #define PSEUDO_NOERRNO(name, syscall_name, args) \ | |
76 | .text; \ | |
77 | ENTRY (name) \ | |
78 | DO_CALL (syscall_name, args) | |
79 | ||
80 | #undef PSEUDO_END_NOERRNO | |
81 | #define PSEUDO_END_NOERRNO(name) \ | |
82 | END (name) | |
83 | ||
84 | #define ret_NOERRNO ret | |
85 | ||
86 | /* The function has to return the error code. */ | |
87 | #undef PSEUDO_ERRVAL | |
88 | #define PSEUDO_ERRVAL(name, syscall_name, args) \ | |
89 | .text; \ | |
90 | ENTRY (name) \ | |
91 | DO_CALL (syscall_name, args); \ | |
92 | clr d1; \ | |
93 | sub d0,d1,d0 | |
94 | ||
95 | #undef PSEUDO_END_ERRVAL | |
96 | #define PSEUDO_END_ERRVAL(name) \ | |
97 | END (name) | |
98 | ||
99 | #define ret_ERRVAL ret | |
100 | ||
101 | #ifndef PIC | |
102 | #define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ | |
103 | #else | |
104 | /* Store (- d0) into errno through the GOT. */ | |
105 | #ifdef _LIBC_REENTRANT | |
106 | #define SYSCALL_ERROR_HANDLER \ | |
107 | 0:movm [d2,a2],(sp); \ | |
108 | add -12,sp; \ | |
109 | 1:mov pc,a2; \ | |
110 | add _GLOBAL_OFFSET_TABLE_-(1b-.),a2; \ | |
111 | clr d2; \ | |
112 | sub d0,d2; \ | |
113 | call __errno_location@PLT,[],0; \ | |
114 | mov d2,(a0); \ | |
115 | add 12,sp; \ | |
116 | movm (sp),[d2,a2]; \ | |
117 | mov -1,d0; \ | |
118 | mov d0,a0; \ | |
119 | jmp L(pseudo_end); | |
120 | /* A quick note: it is assumed that the call to `__errno_location' does | |
121 | not modify the stack! */ | |
122 | #else | |
123 | #define SYSCALL_ERROR_HANDLER \ | |
124 | 0:mov pc,a0; \ | |
125 | add _GLOBAL_OFFSET_TABLE_-(0b-.),a0; \ | |
126 | clr d1; \ | |
127 | sub d0,d1; \ | |
128 | mov (errno@GOT,a0),a1; \ | |
129 | mov d1,(a0); \ | |
130 | mov -1,d0; \ | |
131 | mov d0,a0; \ | |
132 | jmp L(pseudo_end); | |
133 | #endif /* _LIBC_REENTRANT */ | |
134 | #endif /* PIC */ | |
135 | ||
136 | /* Linux takes system call arguments in registers: | |
137 | ||
138 | syscall number d0 call-clobbered | |
139 | arg 1 a0 call-clobbered | |
140 | arg 2 d1 call-clobbered | |
141 | arg 3 a3 call-saved | |
142 | arg 4 a2 call-saved | |
143 | arg 5 d3 call-saved | |
144 | arg 6 d2 call-saved | |
145 | ||
146 | The stack layout upon entering the function is: | |
147 | ||
148 | (24,sp) Arg# 6 | |
149 | (20,sp) Arg# 5 | |
150 | (16,sp) Arg# 4 | |
151 | (12,sp) Arg# 3 | |
152 | d1 Arg# 2 | |
153 | d0 Arg# 1 | |
154 | (sp) Return address | |
155 | ||
156 | (Of course a function with say 3 arguments does not have entries for | |
157 | arguments 4, 5 and 6.) */ | |
158 | ||
159 | #undef DO_CALL | |
160 | #define DO_CALL(syscall_name, args) \ | |
161 | PUSHARGS_##args \ | |
162 | DOARGS_##args \ | |
163 | mov SYS_ify (syscall_name),d0; \ | |
164 | syscall 0 \ | |
165 | POPARGS_##args | |
166 | ||
167 | #define PUSHARGS_0 /* No arguments to push. */ | |
168 | #define _DOARGS_0(N) /* No arguments to frob. */ | |
169 | #define DOARGS_0 /* No arguments to frob. */ | |
170 | #define POPARGS_0 /* No arguments to pop. */ | |
171 | ||
172 | #define PUSHARGS_1 /* No arguments to push. */ | |
173 | #define _DOARGS_1(N) _DOARGS_0 (N-4) mov d0,a0; | |
174 | #define DOARGS_1 _DOARGS_1 (4) | |
175 | #define POPARGS_1 /* No arguments to pop. */ | |
176 | ||
177 | #define PUSHARGS_2 /* No arguments to push. */ | |
178 | #define _DOARGS_2(N) _DOARGS_1 (N-4) /* Argument already in d1. */ | |
179 | #define DOARGS_2 _DOARGS_2 (8) | |
180 | #define POPARGS_2 /* No arguments to pop. */ | |
181 | ||
182 | #define PUSHARGS_3 movm [a3],(sp); | |
183 | #define _DOARGS_3(N) _DOARGS_2 (N-4) mov (N,sp),a3; | |
184 | #define DOARGS_3 _DOARGS_3 (16) | |
185 | #define POPARGS_3 ; movm (sp),[a3] | |
186 | ||
187 | #define PUSHARGS_4 movm [a2,a3],(sp); | |
188 | #define _DOARGS_4(N) _DOARGS_3 (N-4) mov (N,sp),a2; | |
189 | #define DOARGS_4 _DOARGS_4 (24) | |
190 | #define POPARGS_4 ; movm (sp),[a2,a3] | |
191 | ||
192 | #define PUSHARGS_5 movm [d3,a2,a3],(sp); | |
193 | #define _DOARGS_5(N) _DOARGS_4 (N-4) mov (N,sp),d3; | |
194 | #define DOARGS_5 _DOARGS_5 (32) | |
195 | #define POPARGS_5 ; movm (sp),[d3,a2,a3] | |
196 | ||
197 | #define PUSHARGS_6 movm [d2,d3,a2,a3],(sp); | |
198 | #define _DOARGS_6(N) _DOARGS_5 (N-4) mov (N,sp),d2; | |
199 | #define DOARGS_6 _DOARGS_6 (40) | |
200 | #define POPARGS_6 ; movm (sp),[d2,d3,a2,a3] | |
201 | ||
202 | #else /* !__ASSEMBLER__ */ | |
203 | ||
204 | /* Define a macro which expands inline into the wrapper code for a system | |
205 | call. */ | |
206 | #undef INLINE_SYSCALL | |
207 | #define INLINE_SYSCALL(name, nr, args...) \ | |
208 | ({ \ | |
209 | unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args); \ | |
210 | if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (resultvar, ), 0)) \ | |
211 | { \ | |
212 | __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, )); \ | |
213 | resultvar = 0xffffffff; \ | |
214 | } \ | |
215 | (int) resultvar; }) | |
216 | ||
217 | #define INTERNAL_SYSCALL(name, err, nr, args...) \ | |
218 | ({ \ | |
219 | register long __sc0 asm ("d0") = __NR_##name; \ | |
220 | inline_syscall##nr(name, ## args); \ | |
221 | __sc0; \ | |
222 | }) | |
223 | ||
224 | #undef INTERNAL_SYSCALL_DECL | |
225 | #define INTERNAL_SYSCALL_DECL(err) do { } while (0) | |
226 | ||
227 | #undef INTERNAL_SYSCALL_ERROR_P | |
228 | #define INTERNAL_SYSCALL_ERROR_P(val, err) \ | |
229 | ((unsigned int) (val) >= (unsigned long)-125) | |
230 | ||
231 | #undef INTERNAL_SYSCALL_ERRNO | |
232 | #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) | |
233 | ||
234 | #define inline_syscall0(name,dummy...) \ | |
235 | __asm__ __volatile__ ("syscall 0" \ | |
236 | : "+d" (__sc0) \ | |
237 | : : "memory") | |
238 | ||
239 | #define inline_syscall1(name,arg1) \ | |
240 | register long __sc1 asm ("a0") = (long) (arg1); \ | |
241 | inline_syscall0 (name); \ | |
242 | __asm__ __volatile__ ("" : : "r" (__sc1)) | |
243 | ||
244 | #define inline_syscall2(name,arg1,arg2) \ | |
245 | register long __sc2 asm ("d1") = (long) (arg2); \ | |
246 | inline_syscall1 (name,(arg1)); \ | |
247 | __asm__ __volatile__ ("" : : "r" (__sc2)) | |
248 | ||
249 | /* We can't tell whether a3 is going to be eliminated in the enclosing | |
250 | function, so we have to assume it isn't. We first load the value | |
251 | of any arguments into their registers, except for a3 itself, that | |
252 | may be needed to load the value of the other arguments. Then, we | |
253 | save a3's value in some other register, and load the argument value | |
254 | into a3. We have to force both a3 and its copy to be live in | |
255 | different registers at the same time, to avoid having the copy | |
256 | spilled and the value reloaded into the same register, in which | |
257 | case we'd be unable to get the value of a3 back, should the stack | |
258 | slot reference be (offset,a3). */ | |
259 | #define inline_syscall3(name,arg1,arg2,arg3) \ | |
260 | long __sc3v = (long) (arg3); \ | |
261 | register long __sc1 asm ("a0") = (long) (arg1); \ | |
262 | register long __sc2 asm ("d1") = (long) (arg2); \ | |
263 | register long __sc3 asm ("a3") = __sc3; \ | |
264 | register long __sc3c; \ | |
265 | __asm__ __volatile__ ("mov %1,%0" : "=&r" (__sc3c) : "r" (__sc3)); \ | |
266 | __sc3 = __sc3v; \ | |
267 | __asm__ __volatile__ ("" : : "r" (__sc3c), "r" (__sc3)); \ | |
268 | inline_syscall0 (name); \ | |
269 | __sc3 = __sc3c; \ | |
270 | __asm__ __volatile__ ("" : : "r" (__sc3), "r" (__sc2), "r" (__sc1)) | |
271 | ||
272 | #ifdef PIC | |
273 | /* Since a2 is the PIC register, it requires similar handling as a3 | |
274 | when we're generating PIC, as a2's value may be needed to load | |
275 | arguments whose values live in global variables. The difference is | |
276 | that we don't need to require its value to be live in a register; | |
277 | it may well be in a stack slot, as long as we save it before | |
278 | clobbering a3 and restore it after restoring a3. */ | |
279 | #define inline_syscall4(name,arg1,arg2,arg3,arg4) \ | |
280 | long __sc4v = (long) (arg4); \ | |
281 | long __sc3v = (long) (arg3); \ | |
282 | register long __sc1 asm ("a0") = (long) (arg1); \ | |
283 | register long __sc2 asm ("d1") = (long) (arg2); \ | |
284 | register long __sc3 asm ("a3") = __sc3; \ | |
285 | register long __sc3c; \ | |
286 | register long __sc4 asm ("a2") = __sc4; \ | |
287 | long __sc4c = __sc4; \ | |
288 | __sc4 = __sc4v; \ | |
289 | __asm__ __volatile__ ("mov %1,%0" : "=&r" (__sc3c) : "r" (__sc3)); \ | |
290 | __sc3 = __sc3v; \ | |
291 | __asm__ __volatile__ ("" : : "r" (__sc3c), "r" (__sc3), "r" (__sc4)); \ | |
292 | inline_syscall0 (name); \ | |
293 | __sc3 = __sc3c; \ | |
294 | __sc4 = __sc4c; \ | |
295 | __asm__ __volatile__ ("" : : "r" (__sc4), "r" (__sc3), \ | |
296 | "r" (__sc2), "r" (__sc1)) | |
297 | #else | |
298 | #define inline_syscall4(name,arg1,arg2,arg3,arg4) \ | |
299 | register long __sc4 asm ("a2") = (long) (arg4); \ | |
300 | inline_syscall3 (name,(arg1),(arg2),(arg3)); \ | |
301 | __asm__ __volatile__ ("" : : "r" (__sc4)) | |
302 | #endif | |
303 | ||
304 | #define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5) \ | |
305 | register long __sc5 asm ("d3") = (long) (arg5); \ | |
306 | inline_syscall4 (name,(arg1),(arg2),(arg3),(arg4)); \ | |
307 | __asm__ __volatile__ ("" : : "r" (__sc5)) | |
308 | ||
309 | #define inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6) \ | |
310 | register long __sc6 asm ("d2") = (long) (arg6); \ | |
311 | inline_syscall5 (name,(arg1),(arg2),(arg3),(arg4),(arg5)); \ | |
312 | __asm__ __volatile__ ("" : : "r" (__sc6)) | |
313 | ||
314 | #endif /* __ASSEMBLER__ */ | |
315 | ||
316 | #endif /* linux/am33/sysdep.h */ |