]>
Commit | Line | Data |
---|---|---|
b168057a | 1 | /* Copyright (C) 2000-2015 Free Software Foundation, Inc. |
7756ba9d DH |
2 | |
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 License as | |
7 | published by the Free Software Foundation; either version 2.1 of the | |
8 | 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 | #include <sysdeps/microblaze/sysdep.h> | |
20 | #include <sys/syscall.h> | |
21 | ||
22 | /* Defines RTLD_PRIVATE_ERRNO. */ | |
23 | #include <dl-sysdep.h> | |
24 | ||
25 | /* In order to get __set_errno() definition in INLINE_SYSCALL. */ | |
26 | #ifndef __ASSEMBLER__ | |
27 | # include <errno.h> | |
28 | #endif | |
29 | ||
30 | /* For Linux we can use the system call table in the header file | |
31 | /usr/include/asm/unistd.h | |
32 | of the kernel. But these symbols do not follow the SYS_* syntax | |
33 | so we have to redefine the `SYS_ify' macro here. */ | |
34 | #undef SYS_ify | |
35 | #define SYS_ify(syscall_name) __NR_##syscall_name | |
36 | ||
37 | #ifdef __ASSEMBLER__ | |
38 | ||
39 | /* In microblaze ABI function call arguments are passed in registers | |
40 | r5...r10. The return value is stored in r3 (or r3:r4 regiters pair). | |
41 | Linux syscall uses the same convention with the addition that the | |
42 | syscall number is passed in r12. To enter the kernel "brki r14,8" | |
43 | instruction is used. | |
44 | None of the abovementioned registers are presumed across function call | |
45 | or syscall. | |
46 | */ | |
47 | /* Linux uses a negative return value to indicate syscall errors, unlike | |
48 | most Unices, which use the condition codes' carry flag. | |
49 | ||
50 | Since version 2.1 the return value of a system call might be negative | |
51 | even if the call succeeded. E.g., the `lseek' system call might return | |
52 | a large offset. Therefore we must not anymore test for < 0, but test | |
53 | for a real error by making sure the value in %d0 is a real error | |
54 | number. Linus said he will make sure the no syscall returns a value | |
55 | in -1 .. -4095 as a valid result so we can savely test with -4095. */ | |
56 | ||
57 | /* We don't want the label for the error handler to be visible in the symbol | |
58 | table when we define it here. */ | |
59 | # ifdef PIC | |
60 | # define SYSCALL_ERROR_LABEL 0f | |
61 | # else | |
62 | # define SYSCALL_ERROR_LABEL __syscall_error | |
63 | # endif | |
64 | ||
65 | # undef PSEUDO | |
66 | # define PSEUDO(name, syscall_name, args) \ | |
67 | .text; \ | |
68 | ENTRY (name) \ | |
69 | DO_CALL (syscall_name, args); \ | |
70 | addik r12,r0,-4095; \ | |
71 | cmpu r12,r12,r3; \ | |
72 | bgei r12,SYSCALL_ERROR_LABEL; | |
73 | ||
74 | # undef PSEUDO_END | |
75 | # define PSEUDO_END(name) \ | |
76 | SYSCALL_ERROR_HANDLER; \ | |
77 | END (name) | |
78 | ||
79 | # undef PSEUDO_NOERRNO | |
80 | # define PSEUDO_NOERRNO(name, syscall_name, args) \ | |
81 | .text; \ | |
82 | ENTRY (name) \ | |
83 | DO_CALL (syscall_name, args); | |
84 | ||
85 | # undef PSEUDO_END_NOERRNO | |
86 | # define PSEUDO_END_NOERRNO(name) \ | |
87 | END (name) | |
88 | ||
89 | /* The function has to return the error code. */ | |
90 | # undef PSEUDO_ERRVAL | |
91 | # define PSEUDO_ERRVAL(name, syscall_name, args) \ | |
92 | .text; \ | |
93 | ENTRY (name) \ | |
94 | DO_CALL (syscall_name, args); \ | |
95 | ||
96 | # undef PSEUDO_END_ERRVAL | |
97 | # define PSEUDO_END_ERRVAL(name) \ | |
98 | END (name) | |
99 | ||
100 | # define ret_NOERRNO \ | |
101 | rtsd r15,8; addk r0,r0,r0; | |
102 | ||
103 | # define ret_ERRVAL \ | |
104 | rtsd r15,8; rsubk r3,r3,r0; | |
105 | ||
106 | # ifdef PIC | |
107 | # define SYSCALL_ERROR_LABEL_DCL 0 | |
108 | # if RTLD_PRIVATE_ERRNO | |
109 | # define SYSCALL_ERROR_HANDLER \ | |
110 | SYSCALL_ERROR_LABEL_DCL: \ | |
111 | mfs r12,rpc; \ | |
112 | addik r12,r12,_GLOBAL_OFFSET_TABLE_+8; \ | |
113 | lwi r12,r12,rtld_errno@GOT; \ | |
114 | rsubk r3,r3,r0; \ | |
115 | swi r3,r12,0; \ | |
116 | rtsd r15,8; \ | |
117 | addik r3,r0,-1; | |
118 | # else /* !RTLD_PRIVATE_ERRNO. */ | |
119 | /* Store (-r3) into errno through the GOT. */ | |
120 | # if defined _LIBC_REENTRANT | |
121 | # define SYSCALL_ERROR_HANDLER \ | |
122 | SYSCALL_ERROR_LABEL_DCL: \ | |
123 | addik r1,r1,-16; \ | |
124 | swi r15,r1,0; \ | |
125 | swi r20,r1,8; \ | |
126 | rsubk r3,r3,r0; \ | |
127 | swi r3,r1,12; \ | |
128 | mfs r20,rpc; \ | |
129 | addik r20,r20,_GLOBAL_OFFSET_TABLE_+8; \ | |
130 | brlid r15,__errno_location@PLT; \ | |
131 | nop; \ | |
132 | lwi r4,r1,12; \ | |
133 | swi r4,r3,0; \ | |
134 | lwi r20,r1,8; \ | |
135 | lwi r15,r1,0; \ | |
136 | addik r1,r1,16; \ | |
137 | rtsd r15,8; \ | |
138 | addik r3,r0,-1; | |
139 | # else /* !_LIBC_REENTRANT. */ | |
140 | # define SYSCALL_ERROR_HANDLER \ | |
141 | SYSCALL_ERROR_LABEL_DCL: \ | |
142 | mfs r12,rpc; \ | |
143 | addik r12,r12,_GLOBAL_OFFSET_TABLE_+8; \ | |
144 | lwi r12,r12,errno@GOT; \ | |
145 | rsubk r3,r3,r0; \ | |
146 | swi r3,r12,0; \ | |
147 | rtsd r15,8; \ | |
148 | addik r3,r0,-1; | |
149 | # endif /* _LIBC_REENTRANT. */ | |
150 | # endif /* RTLD_PRIVATE_ERRNO. */ | |
151 | # else | |
152 | # define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ | |
153 | # endif /* PIC. */ | |
154 | ||
155 | # define DO_CALL(syscall_name, args) \ | |
156 | addik r12,r0,SYS_ify (syscall_name); \ | |
157 | brki r14,8; \ | |
158 | addk r0,r0,r0; | |
159 | ||
160 | #else /* not __ASSEMBLER__ */ | |
161 | ||
162 | /* Define a macro which expands into the inline wrapper code for a system | |
163 | call. */ | |
164 | # undef INLINE_SYSCALL | |
165 | # define INLINE_SYSCALL(name, nr, args...) \ | |
166 | ({ INTERNAL_SYSCALL_DECL(err); \ | |
167 | unsigned long resultvar = INTERNAL_SYSCALL(name, err, nr, args); \ | |
168 | if (INTERNAL_SYSCALL_ERROR_P (resultvar, err)) \ | |
169 | { \ | |
170 | __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, err)); \ | |
171 | resultvar = (unsigned long) -1; \ | |
172 | } \ | |
173 | (long) resultvar; \ | |
174 | }) | |
175 | ||
176 | # undef INTERNAL_SYSCALL_DECL | |
177 | # define INTERNAL_SYSCALL_DECL(err) do { } while (0) | |
178 | ||
179 | /* Define a macro which expands inline into the wrapper code for a system | |
180 | call. This use is for internal calls that do not need to handle errors | |
181 | normally. It will never touch errno. This returns just what the kernel | |
182 | gave back. */ | |
183 | # undef INTERNAL_SYSCALL | |
184 | # define INTERNAL_SYSCALL(name, err, nr, args...) \ | |
185 | inline_syscall##nr(SYS_ify(name), args) | |
186 | ||
187 | # undef INTERNAL_SYSCALL_NCS | |
188 | # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ | |
189 | inline_syscall##nr(name, args) | |
190 | ||
191 | # undef INTERNAL_SYSCALL_ERROR_P | |
192 | # define INTERNAL_SYSCALL_ERROR_P(val, err) \ | |
193 | ((unsigned int) (val) >= -4095U) | |
194 | ||
195 | # undef INTERNAL_SYSCALL_ERRNO | |
196 | # define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) | |
197 | ||
198 | # define SYSCALL_CLOBBERS_6 "r11", "r4", "memory" | |
199 | # define SYSCALL_CLOBBERS_5 "r10", SYSCALL_CLOBBERS_6 | |
200 | # define SYSCALL_CLOBBERS_4 "r9", SYSCALL_CLOBBERS_5 | |
201 | # define SYSCALL_CLOBBERS_3 "r8", SYSCALL_CLOBBERS_4 | |
202 | # define SYSCALL_CLOBBERS_2 "r7", SYSCALL_CLOBBERS_3 | |
203 | # define SYSCALL_CLOBBERS_1 "r6", SYSCALL_CLOBBERS_2 | |
204 | # define SYSCALL_CLOBBERS_0 "r5", SYSCALL_CLOBBERS_1 | |
205 | ||
206 | # define inline_syscall0(name,dummy) \ | |
207 | ({ \ | |
208 | register long ret __asm__("r3"); \ | |
209 | register long __r12 __asm__("r12") = name; \ | |
210 | __asm__ __volatile__( "brki r14,8; nop;" \ | |
211 | : "=r"(ret) \ | |
212 | : "r"(__r12) \ | |
213 | : SYSCALL_CLOBBERS_0 ); ret; \ | |
214 | }) | |
215 | ||
216 | # define inline_syscall1(name,arg1) \ | |
217 | ({ \ | |
218 | register long ret __asm__("r3"); \ | |
219 | register long __r12 __asm__("r12") = name; \ | |
220 | register long __r5 __asm__("r5") = (long)(arg1); \ | |
221 | __asm__ __volatile__( "brki r14,8; nop;" \ | |
222 | : "=r"(ret) \ | |
223 | : "r"(__r5), "r"(__r12) \ | |
224 | : SYSCALL_CLOBBERS_1 ); ret; \ | |
225 | }) | |
226 | ||
227 | # define inline_syscall2(name,arg1,arg2) \ | |
228 | ({ \ | |
229 | register long ret __asm__("r3"); \ | |
230 | register long __r12 __asm__("r12") = name; \ | |
231 | register long __r5 __asm__("r5") = (long)(arg1); \ | |
232 | register long __r6 __asm__("r6") = (long)(arg2); \ | |
233 | __asm__ __volatile__( "brki r14,8; nop;" \ | |
234 | : "=r"(ret) \ | |
235 | : "r"(__r5), "r"(__r6), "r"(__r12) \ | |
236 | : SYSCALL_CLOBBERS_2 ); ret; \ | |
237 | }) | |
238 | ||
239 | ||
240 | # define inline_syscall3(name,arg1,arg2,arg3) \ | |
241 | ({ \ | |
242 | register long ret __asm__("r3"); \ | |
243 | register long __r12 __asm__("r12") = name; \ | |
244 | register long __r5 __asm__("r5") = (long)(arg1); \ | |
245 | register long __r6 __asm__("r6") = (long)(arg2); \ | |
246 | register long __r7 __asm__("r7") = (long)(arg3); \ | |
247 | __asm__ __volatile__( "brki r14,8; nop;" \ | |
248 | : "=r"(ret) \ | |
249 | : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r12) \ | |
250 | : SYSCALL_CLOBBERS_3 ); ret; \ | |
251 | }) | |
252 | ||
253 | ||
254 | # define inline_syscall4(name,arg1,arg2,arg3,arg4) \ | |
255 | ({ \ | |
256 | register long ret __asm__("r3"); \ | |
257 | register long __r12 __asm__("r12") = name; \ | |
258 | register long __r5 __asm__("r5") = (long)(arg1); \ | |
259 | register long __r6 __asm__("r6") = (long)(arg2); \ | |
260 | register long __r7 __asm__("r7") = (long)(arg3); \ | |
261 | register long __r8 __asm__("r8") = (long)(arg4); \ | |
262 | __asm__ __volatile__( "brki r14,8; nop;" \ | |
263 | : "=r"(ret) \ | |
264 | : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r12) \ | |
265 | : SYSCALL_CLOBBERS_4 ); ret; \ | |
266 | }) | |
267 | ||
268 | ||
269 | # define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5) \ | |
270 | ({ \ | |
271 | register long ret __asm__("r3"); \ | |
272 | register long __r12 __asm__("r12") = name; \ | |
273 | register long __r5 __asm__("r5") = (long)(arg1); \ | |
274 | register long __r6 __asm__("r6") = (long)(arg2); \ | |
275 | register long __r7 __asm__("r7") = (long)(arg3); \ | |
276 | register long __r8 __asm__("r8") = (long)(arg4); \ | |
277 | register long __r9 __asm__("r9") = (long)(arg5); \ | |
278 | __asm__ __volatile__( "brki r14,8; nop;" \ | |
279 | : "=r"(ret) \ | |
280 | : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r9), "r"(__r12) \ | |
281 | : SYSCALL_CLOBBERS_5 ); ret; \ | |
282 | }) | |
283 | ||
284 | ||
285 | # define inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6) \ | |
286 | ({ \ | |
287 | register long ret __asm__("r3"); \ | |
288 | register long __r12 __asm__("r12") = name; \ | |
289 | register long __r5 __asm__("r5") = (long)(arg1); \ | |
290 | register long __r6 __asm__("r6") = (long)(arg2); \ | |
291 | register long __r7 __asm__("r7") = (long)(arg3); \ | |
292 | register long __r8 __asm__("r8") = (long)(arg4); \ | |
293 | register long __r9 __asm__("r9") = (long)(arg5); \ | |
294 | register long __r10 __asm__("r10") = (long)(arg6); \ | |
295 | __asm__ __volatile__( "brki r14,8; nop;" \ | |
296 | : "=r"(ret) \ | |
297 | : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r9), "r"(__r10), \ | |
298 | "r"(__r12) \ | |
299 | : SYSCALL_CLOBBERS_6 ); ret; \ | |
300 | }) | |
301 | ||
302 | ||
303 | /* Pointer mangling is not yet supported for Microblaze. */ | |
304 | # define PTR_MANGLE(var) (void) (var) | |
305 | # define PTR_DEMANGLE(var) (void) (var) | |
306 | ||
307 | #endif /* not __ASSEMBLER__ */ |