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