]>
Commit | Line | Data |
---|---|---|
04277e02 | 1 | /* Copyright (C) 2000-2019 Free Software Foundation, Inc. |
87af90e7 AJ |
2 | This file is part of the GNU C Library. |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
3214b89b AJ |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
87af90e7 AJ |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
3214b89b | 12 | Lesser General Public License for more details. |
87af90e7 | 13 | |
3214b89b | 14 | You should have received a copy of the GNU Lesser General Public |
ab84e3ff | 15 | License along with the GNU C Library. If not, see |
5a82c748 | 16 | <https://www.gnu.org/licenses/>. */ |
87af90e7 | 17 | |
ef055a74 AO |
18 | #ifndef _LINUX_MIPS_MIPS32_SYSDEP_H |
19 | #define _LINUX_MIPS_MIPS32_SYSDEP_H 1 | |
87af90e7 AJ |
20 | |
21 | /* There is some commonality. */ | |
b8386c28 | 22 | #include <sysdeps/unix/sysv/linux/mips/sysdep.h> |
fb1cf108 | 23 | #include <sysdeps/unix/sysv/linux/sysdep.h> |
ef055a74 | 24 | #include <sysdeps/unix/mips/mips32/sysdep.h> |
87af90e7 | 25 | |
8c276674 DJ |
26 | #include <tls.h> |
27 | ||
340f7976 JM |
28 | /* In order to get __set_errno() definition in INLINE_SYSCALL. */ |
29 | #ifndef __ASSEMBLER__ | |
30 | #include <errno.h> | |
31 | #endif | |
32 | ||
87af90e7 AJ |
33 | /* For Linux we can use the system call table in the header file |
34 | /usr/include/asm/unistd.h | |
35 | of the kernel. But these symbols do not follow the SYS_* syntax | |
36 | so we have to redefine the `SYS_ify' macro here. */ | |
37 | #undef SYS_ify | |
2aee8949 | 38 | #define SYS_ify(syscall_name) __NR_##syscall_name |
87af90e7 | 39 | |
a31567f4 RM |
40 | #ifdef __ASSEMBLER__ |
41 | ||
42 | /* We don't want the label for the error handler to be visible in the symbol | |
43 | table when we define it here. */ | |
44 | #ifdef __PIC__ | |
45 | # define SYSCALL_ERROR_LABEL 99b | |
46 | #endif | |
47 | ||
48 | #else /* ! __ASSEMBLER__ */ | |
9da3df10 UD |
49 | |
50 | /* Define a macro which expands into the inline wrapper code for a system | |
51 | call. */ | |
52 | #undef INLINE_SYSCALL | |
53 | #define INLINE_SYSCALL(name, nr, args...) \ | |
e0c349b4 JM |
54 | ({ INTERNAL_SYSCALL_DECL (_sc_err); \ |
55 | long result_var = INTERNAL_SYSCALL (name, _sc_err, nr, args); \ | |
56 | if ( INTERNAL_SYSCALL_ERROR_P (result_var, _sc_err) ) \ | |
e1ae85a5 | 57 | { \ |
e0c349b4 | 58 | __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, _sc_err)); \ |
e1ae85a5 AJ |
59 | result_var = -1L; \ |
60 | } \ | |
9da3df10 UD |
61 | result_var; }) |
62 | ||
63 | #undef INTERNAL_SYSCALL_DECL | |
6eb43a28 | 64 | #define INTERNAL_SYSCALL_DECL(err) long err __attribute__ ((unused)) |
9da3df10 UD |
65 | |
66 | #undef INTERNAL_SYSCALL_ERROR_P | |
6eb43a28 | 67 | #define INTERNAL_SYSCALL_ERROR_P(val, err) ((void) (val), (long) (err)) |
9da3df10 UD |
68 | |
69 | #undef INTERNAL_SYSCALL_ERRNO | |
6eb43a28 | 70 | #define INTERNAL_SYSCALL_ERRNO(val, err) ((void) (err), val) |
9da3df10 | 71 | |
b82ba2f0 MR |
72 | /* Note that the original Linux syscall restart convention required the |
73 | instruction immediately preceding SYSCALL to initialize $v0 with the | |
74 | syscall number. Then if a restart triggered, $v0 would have been | |
75 | clobbered by the syscall interrupted, and needed to be reinititalized. | |
76 | The kernel would decrement the PC by 4 before switching back to the | |
77 | user mode so that $v0 had been reloaded before SYSCALL was executed | |
78 | again. This implied the place $v0 was loaded from must have been | |
79 | preserved across a syscall, e.g. an immediate, static register, stack | |
80 | slot, etc. | |
81 | ||
82 | The convention was relaxed in Linux with a change applied to the kernel | |
83 | GIT repository as commit 96187fb0bc30cd7919759d371d810e928048249d, that | |
84 | first appeared in the 2.6.36 release. Since then the kernel has had | |
85 | code that reloads $v0 upon syscall restart and resumes right at the | |
86 | SYSCALL instruction, so no special arrangement is needed anymore. | |
87 | ||
88 | For backwards compatibility with existing kernel binaries we support | |
89 | the old convention by choosing the instruction preceding SYSCALL | |
90 | carefully. This also means we have to force a 32-bit encoding of the | |
91 | microMIPS MOVE instruction if one is used. */ | |
92 | ||
93 | #ifdef __mips_micromips | |
94 | # define MOVE32 "move32" | |
95 | #else | |
96 | # define MOVE32 "move" | |
97 | #endif | |
98 | ||
9da3df10 | 99 | #undef INTERNAL_SYSCALL |
43301bd3 MR |
100 | #undef INTERNAL_SYSCALL_NCS |
101 | ||
319cbbf6 AZ |
102 | #define __nomips16 __attribute__ ((nomips16)) |
103 | ||
104 | union __mips_syscall_return | |
105 | { | |
106 | long long val; | |
107 | struct | |
108 | { | |
109 | long v0; | |
110 | long v1; | |
111 | } | |
112 | reg; | |
113 | }; | |
114 | ||
43301bd3 MR |
115 | #ifdef __mips16 |
116 | /* There's no MIPS16 syscall instruction, so we go through out-of-line | |
117 | standard MIPS wrappers. These do use inline snippets below though, | |
118 | through INTERNAL_SYSCALL_MIPS16. Spilling the syscall number to | |
119 | memory gives the best code in that case, avoiding the need to save | |
120 | and restore a static register. */ | |
121 | ||
122 | # include <mips16-syscall.h> | |
123 | ||
124 | # define INTERNAL_SYSCALL(name, err, nr, args...) \ | |
125 | INTERNAL_SYSCALL_NCS (SYS_ify (name), err, nr, args) | |
126 | ||
127 | # define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ | |
128 | ({ \ | |
319cbbf6 | 129 | union __mips_syscall_return _sc_ret; \ |
e0c349b4 JM |
130 | _sc_ret.val = __mips16_syscall##nr (args, number); \ |
131 | err = _sc_ret.reg.v1; \ | |
132 | _sc_ret.reg.v0; \ | |
43301bd3 MR |
133 | }) |
134 | ||
135 | # define INTERNAL_SYSCALL_MIPS16(number, err, nr, args...) \ | |
136 | internal_syscall##nr ("lw\t%0, %2\n\t", \ | |
137 | "R" (number), \ | |
319cbbf6 | 138 | number, err, args) |
43301bd3 MR |
139 | |
140 | #else /* !__mips16 */ | |
141 | # define INTERNAL_SYSCALL(name, err, nr, args...) \ | |
b82ba2f0 MR |
142 | internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t", \ |
143 | "IK" (SYS_ify (name)), \ | |
319cbbf6 | 144 | SYS_ify (name), err, args) |
9da3df10 | 145 | |
43301bd3 | 146 | # define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ |
b82ba2f0 MR |
147 | internal_syscall##nr (MOVE32 "\t%0, %2\n\t", \ |
148 | "r" (__s0), \ | |
149 | number, err, args) | |
e1ae85a5 | 150 | |
43301bd3 MR |
151 | #endif /* !__mips16 */ |
152 | ||
b82ba2f0 | 153 | #define internal_syscall0(v0_init, input, number, err, dummy...) \ |
e1ae85a5 | 154 | ({ \ |
9da3df10 UD |
155 | long _sys_result; \ |
156 | \ | |
157 | { \ | |
f9834ea4 | 158 | register long __s0 asm ("$16") __attribute__ ((unused)) \ |
b82ba2f0 | 159 | = (number); \ |
f9834ea4 MR |
160 | register long __v0 asm ("$2"); \ |
161 | register long __a3 asm ("$7"); \ | |
e1ae85a5 AJ |
162 | __asm__ volatile ( \ |
163 | ".set\tnoreorder\n\t" \ | |
b82ba2f0 | 164 | v0_init \ |
e1ae85a5 AJ |
165 | "syscall\n\t" \ |
166 | ".set reorder" \ | |
167 | : "=r" (__v0), "=r" (__a3) \ | |
168 | : input \ | |
169 | : __SYSCALL_CLOBBERS); \ | |
9da3df10 UD |
170 | err = __a3; \ |
171 | _sys_result = __v0; \ | |
172 | } \ | |
173 | _sys_result; \ | |
174 | }) | |
175 | ||
b82ba2f0 | 176 | #define internal_syscall1(v0_init, input, number, err, arg1) \ |
e1ae85a5 | 177 | ({ \ |
9da3df10 UD |
178 | long _sys_result; \ |
179 | \ | |
180 | { \ | |
f9834ea4 | 181 | register long __s0 asm ("$16") __attribute__ ((unused)) \ |
b82ba2f0 | 182 | = (number); \ |
f9834ea4 MR |
183 | register long __v0 asm ("$2"); \ |
184 | register long __a0 asm ("$4") = (long) (arg1); \ | |
185 | register long __a3 asm ("$7"); \ | |
e1ae85a5 AJ |
186 | __asm__ volatile ( \ |
187 | ".set\tnoreorder\n\t" \ | |
b82ba2f0 | 188 | v0_init \ |
e1ae85a5 AJ |
189 | "syscall\n\t" \ |
190 | ".set reorder" \ | |
191 | : "=r" (__v0), "=r" (__a3) \ | |
192 | : input, "r" (__a0) \ | |
193 | : __SYSCALL_CLOBBERS); \ | |
9da3df10 UD |
194 | err = __a3; \ |
195 | _sys_result = __v0; \ | |
196 | } \ | |
197 | _sys_result; \ | |
198 | }) | |
199 | ||
b82ba2f0 | 200 | #define internal_syscall2(v0_init, input, number, err, arg1, arg2) \ |
e1ae85a5 | 201 | ({ \ |
9da3df10 UD |
202 | long _sys_result; \ |
203 | \ | |
204 | { \ | |
f9834ea4 | 205 | register long __s0 asm ("$16") __attribute__ ((unused)) \ |
b82ba2f0 | 206 | = (number); \ |
f9834ea4 MR |
207 | register long __v0 asm ("$2"); \ |
208 | register long __a0 asm ("$4") = (long) (arg1); \ | |
209 | register long __a1 asm ("$5") = (long) (arg2); \ | |
210 | register long __a3 asm ("$7"); \ | |
e1ae85a5 AJ |
211 | __asm__ volatile ( \ |
212 | ".set\tnoreorder\n\t" \ | |
b82ba2f0 | 213 | v0_init \ |
e1ae85a5 | 214 | "syscall\n\t" \ |
b82ba2f0 | 215 | ".set\treorder" \ |
e1ae85a5 AJ |
216 | : "=r" (__v0), "=r" (__a3) \ |
217 | : input, "r" (__a0), "r" (__a1) \ | |
218 | : __SYSCALL_CLOBBERS); \ | |
9da3df10 UD |
219 | err = __a3; \ |
220 | _sys_result = __v0; \ | |
221 | } \ | |
222 | _sys_result; \ | |
223 | }) | |
224 | ||
b82ba2f0 MR |
225 | #define internal_syscall3(v0_init, input, number, err, \ |
226 | arg1, arg2, arg3) \ | |
e1ae85a5 | 227 | ({ \ |
9da3df10 UD |
228 | long _sys_result; \ |
229 | \ | |
230 | { \ | |
f9834ea4 | 231 | register long __s0 asm ("$16") __attribute__ ((unused)) \ |
b82ba2f0 | 232 | = (number); \ |
f9834ea4 MR |
233 | register long __v0 asm ("$2"); \ |
234 | register long __a0 asm ("$4") = (long) (arg1); \ | |
235 | register long __a1 asm ("$5") = (long) (arg2); \ | |
236 | register long __a2 asm ("$6") = (long) (arg3); \ | |
237 | register long __a3 asm ("$7"); \ | |
e1ae85a5 AJ |
238 | __asm__ volatile ( \ |
239 | ".set\tnoreorder\n\t" \ | |
b82ba2f0 | 240 | v0_init \ |
e1ae85a5 | 241 | "syscall\n\t" \ |
b82ba2f0 | 242 | ".set\treorder" \ |
e1ae85a5 AJ |
243 | : "=r" (__v0), "=r" (__a3) \ |
244 | : input, "r" (__a0), "r" (__a1), "r" (__a2) \ | |
245 | : __SYSCALL_CLOBBERS); \ | |
9da3df10 UD |
246 | err = __a3; \ |
247 | _sys_result = __v0; \ | |
248 | } \ | |
249 | _sys_result; \ | |
250 | }) | |
251 | ||
b82ba2f0 MR |
252 | #define internal_syscall4(v0_init, input, number, err, \ |
253 | arg1, arg2, arg3, arg4) \ | |
e1ae85a5 | 254 | ({ \ |
9da3df10 UD |
255 | long _sys_result; \ |
256 | \ | |
257 | { \ | |
f9834ea4 | 258 | register long __s0 asm ("$16") __attribute__ ((unused)) \ |
b82ba2f0 | 259 | = (number); \ |
f9834ea4 MR |
260 | register long __v0 asm ("$2"); \ |
261 | register long __a0 asm ("$4") = (long) (arg1); \ | |
262 | register long __a1 asm ("$5") = (long) (arg2); \ | |
263 | register long __a2 asm ("$6") = (long) (arg3); \ | |
264 | register long __a3 asm ("$7") = (long) (arg4); \ | |
e1ae85a5 AJ |
265 | __asm__ volatile ( \ |
266 | ".set\tnoreorder\n\t" \ | |
b82ba2f0 | 267 | v0_init \ |
e1ae85a5 | 268 | "syscall\n\t" \ |
b82ba2f0 | 269 | ".set\treorder" \ |
e1ae85a5 AJ |
270 | : "=r" (__v0), "+r" (__a3) \ |
271 | : input, "r" (__a0), "r" (__a1), "r" (__a2) \ | |
272 | : __SYSCALL_CLOBBERS); \ | |
9da3df10 UD |
273 | err = __a3; \ |
274 | _sys_result = __v0; \ | |
275 | } \ | |
276 | _sys_result; \ | |
277 | }) | |
278 | ||
319cbbf6 AZ |
279 | /* Standalone MIPS wrappers used for 5, 6, and 7 argument syscalls, |
280 | which require stack arguments. We rely on the compiler arranging | |
281 | wrapper's arguments according to the MIPS o32 function calling | |
282 | convention, which is reused by syscalls, except for the syscall | |
283 | number passed and the error flag returned (taken care of in the | |
284 | wrapper called). This relieves us from relying on non-guaranteed | |
285 | compiler specifics required for the stack arguments to be pushed, | |
286 | which would be the case if these syscalls were inlined. */ | |
287 | ||
288 | long long __nomips16 __mips_syscall5 (long arg1, long arg2, long arg3, | |
289 | long arg4, long arg5, | |
290 | long number); | |
291 | libc_hidden_proto (__mips_syscall5, nomips16) | |
e1ae85a5 | 292 | |
b82ba2f0 MR |
293 | #define internal_syscall5(v0_init, input, number, err, \ |
294 | arg1, arg2, arg3, arg4, arg5) \ | |
e1ae85a5 | 295 | ({ \ |
319cbbf6 AZ |
296 | union __mips_syscall_return _sc_ret; \ |
297 | _sc_ret.val = __mips_syscall5 ((long) (arg1), \ | |
298 | (long) (arg2), \ | |
299 | (long) (arg3), \ | |
300 | (long) (arg4), \ | |
301 | (long) (arg5), \ | |
302 | (long) (number)); \ | |
303 | err = _sc_ret.reg.v1; \ | |
304 | _sc_ret.reg.v0; \ | |
9da3df10 UD |
305 | }) |
306 | ||
319cbbf6 AZ |
307 | long long __nomips16 __mips_syscall6 (long arg1, long arg2, long arg3, |
308 | long arg4, long arg5, long arg6, | |
309 | long number); | |
310 | libc_hidden_proto (__mips_syscall6, nomips16) | |
311 | ||
b82ba2f0 MR |
312 | #define internal_syscall6(v0_init, input, number, err, \ |
313 | arg1, arg2, arg3, arg4, arg5, arg6) \ | |
e1ae85a5 | 314 | ({ \ |
319cbbf6 AZ |
315 | union __mips_syscall_return _sc_ret; \ |
316 | _sc_ret.val = __mips_syscall6 ((long) (arg1), \ | |
317 | (long) (arg2), \ | |
318 | (long) (arg3), \ | |
319 | (long) (arg4), \ | |
320 | (long) (arg5), \ | |
321 | (long) (arg6), \ | |
322 | (long) (number)); \ | |
323 | err = _sc_ret.reg.v1; \ | |
324 | _sc_ret.reg.v0; \ | |
9da3df10 UD |
325 | }) |
326 | ||
319cbbf6 AZ |
327 | long long __nomips16 __mips_syscall7 (long arg1, long arg2, long arg3, |
328 | long arg4, long arg5, long arg6, | |
329 | long arg7, | |
330 | long number); | |
331 | libc_hidden_proto (__mips_syscall7, nomips16) | |
332 | ||
b82ba2f0 MR |
333 | #define internal_syscall7(v0_init, input, number, err, \ |
334 | arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ | |
e1ae85a5 | 335 | ({ \ |
319cbbf6 AZ |
336 | union __mips_syscall_return _sc_ret; \ |
337 | _sc_ret.val = __mips_syscall7 ((long) (arg1), \ | |
338 | (long) (arg2), \ | |
339 | (long) (arg3), \ | |
340 | (long) (arg4), \ | |
341 | (long) (arg5), \ | |
342 | (long) (arg6), \ | |
343 | (long) (arg7), \ | |
344 | (long) (number)); \ | |
345 | err = _sc_ret.reg.v1; \ | |
346 | _sc_ret.reg.v0; \ | |
9da3df10 UD |
347 | }) |
348 | ||
145f3f8a | 349 | #define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \ |
f1297d79 | 350 | "$14", "$15", "$24", "$25", "hi", "lo", "memory" |
9da3df10 UD |
351 | |
352 | #endif /* __ASSEMBLER__ */ | |
353 | ||
908afa83 DJ |
354 | /* Pointer mangling is not yet supported for MIPS. */ |
355 | #define PTR_MANGLE(var) (void) (var) | |
356 | #define PTR_DEMANGLE(var) (void) (var) | |
357 | ||
ef055a74 | 358 | #endif /* linux/mips/mips32/sysdep.h */ |