]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
c2fe86d1cdb4144558dc169f0bb267b27cab622a
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / mips / mips64 / n64 / sysdep.h
1 /* Copyright (C) 2000-2019 Free Software Foundation, Inc.
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
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.
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
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library. If not, see
16 <https://www.gnu.org/licenses/>. */
17
18 #ifndef _LINUX_MIPS_SYSDEP_H
19 #define _LINUX_MIPS_SYSDEP_H 1
20
21 /* There is some commonality. */
22 #include <sysdeps/unix/sysv/linux/sysdep.h>
23 #include <sysdeps/unix/mips/mips64/n64/sysdep.h>
24
25 #include <tls.h>
26
27 /* In order to get __set_errno() definition in INLINE_SYSCALL. */
28 #ifndef __ASSEMBLER__
29 #include <errno.h>
30 #endif
31
32 /* For Linux we can use the system call table in the header file
33 /usr/include/asm/unistd.h
34 of the kernel. But these symbols do not follow the SYS_* syntax
35 so we have to redefine the `SYS_ify' macro here. */
36 #undef SYS_ify
37 #define SYS_ify(syscall_name) __NR_##syscall_name
38
39 #ifdef __ASSEMBLER__
40
41 /* We don't want the label for the error handler to be visible in the symbol
42 table when we define it here. */
43 # define SYSCALL_ERROR_LABEL 99b
44
45 #else /* ! __ASSEMBLER__ */
46
47 /* Define a macro which expands into the inline wrapper code for a system
48 call. */
49 #undef INLINE_SYSCALL
50 #define INLINE_SYSCALL(name, nr, args...) \
51 ({ INTERNAL_SYSCALL_DECL (_sc_err); \
52 long result_var = INTERNAL_SYSCALL (name, _sc_err, nr, args); \
53 if ( INTERNAL_SYSCALL_ERROR_P (result_var, _sc_err) ) \
54 { \
55 __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, _sc_err)); \
56 result_var = -1L; \
57 } \
58 result_var; })
59
60 #undef INTERNAL_SYSCALL_DECL
61 #define INTERNAL_SYSCALL_DECL(err) long err __attribute__ ((unused))
62
63 #undef INTERNAL_SYSCALL_ERROR_P
64 #define INTERNAL_SYSCALL_ERROR_P(val, err) ((void) (val), (long) (err))
65
66 #undef INTERNAL_SYSCALL_ERRNO
67 #define INTERNAL_SYSCALL_ERRNO(val, err) ((void) (err), val)
68
69 /* Note that the original Linux syscall restart convention required the
70 instruction immediately preceding SYSCALL to initialize $v0 with the
71 syscall number. Then if a restart triggered, $v0 would have been
72 clobbered by the syscall interrupted, and needed to be reinititalized.
73 The kernel would decrement the PC by 4 before switching back to the
74 user mode so that $v0 had been reloaded before SYSCALL was executed
75 again. This implied the place $v0 was loaded from must have been
76 preserved across a syscall, e.g. an immediate, static register, stack
77 slot, etc.
78
79 The convention was relaxed in Linux with a change applied to the kernel
80 GIT repository as commit 96187fb0bc30cd7919759d371d810e928048249d, that
81 first appeared in the 2.6.36 release. Since then the kernel has had
82 code that reloads $v0 upon syscall restart and resumes right at the
83 SYSCALL instruction, so no special arrangement is needed anymore.
84
85 For backwards compatibility with existing kernel binaries we support
86 the old convention by choosing the instruction preceding SYSCALL
87 carefully. This also means we have to force a 32-bit encoding of the
88 microMIPS MOVE instruction if one is used. */
89
90 #ifdef __mips_micromips
91 # define MOVE32 "move32"
92 #else
93 # define MOVE32 "move"
94 #endif
95
96 #undef INTERNAL_SYSCALL
97 #define INTERNAL_SYSCALL(name, err, nr, args...) \
98 internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t", \
99 "IK" (SYS_ify (name)), \
100 0, err, args)
101
102 #undef INTERNAL_SYSCALL_NCS
103 #define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
104 internal_syscall##nr (MOVE32 "\t%0, %2\n\t", \
105 "r" (__s0), \
106 number, err, args)
107
108 #define internal_syscall0(v0_init, input, number, err, dummy...) \
109 ({ \
110 long _sys_result; \
111 \
112 { \
113 register long __s0 asm ("$16") __attribute__ ((unused)) \
114 = (number); \
115 register long __v0 asm ("$2"); \
116 register long __a3 asm ("$7"); \
117 __asm__ volatile ( \
118 ".set\tnoreorder\n\t" \
119 v0_init \
120 "syscall\n\t" \
121 ".set reorder" \
122 : "=r" (__v0), "=r" (__a3) \
123 : input \
124 : __SYSCALL_CLOBBERS); \
125 err = __a3; \
126 _sys_result = __v0; \
127 } \
128 _sys_result; \
129 })
130
131 #define internal_syscall1(v0_init, input, number, err, arg1) \
132 ({ \
133 long _sys_result; \
134 \
135 { \
136 register long __s0 asm ("$16") __attribute__ ((unused)) \
137 = (number); \
138 register long __v0 asm ("$2"); \
139 register long __a0 asm ("$4") = (long) (arg1); \
140 register long __a3 asm ("$7"); \
141 __asm__ volatile ( \
142 ".set\tnoreorder\n\t" \
143 v0_init \
144 "syscall\n\t" \
145 ".set reorder" \
146 : "=r" (__v0), "=r" (__a3) \
147 : input, "r" (__a0) \
148 : __SYSCALL_CLOBBERS); \
149 err = __a3; \
150 _sys_result = __v0; \
151 } \
152 _sys_result; \
153 })
154
155 #define internal_syscall2(v0_init, input, number, err, arg1, arg2) \
156 ({ \
157 long _sys_result; \
158 \
159 { \
160 register long __s0 asm ("$16") __attribute__ ((unused)) \
161 = (number); \
162 register long __v0 asm ("$2"); \
163 register long __a0 asm ("$4") = (long) (arg1); \
164 register long __a1 asm ("$5") = (long) (arg2); \
165 register long __a3 asm ("$7"); \
166 __asm__ volatile ( \
167 ".set\tnoreorder\n\t" \
168 v0_init \
169 "syscall\n\t" \
170 ".set\treorder" \
171 : "=r" (__v0), "=r" (__a3) \
172 : input, "r" (__a0), "r" (__a1) \
173 : __SYSCALL_CLOBBERS); \
174 err = __a3; \
175 _sys_result = __v0; \
176 } \
177 _sys_result; \
178 })
179
180 #define internal_syscall3(v0_init, input, number, err, \
181 arg1, arg2, arg3) \
182 ({ \
183 long _sys_result; \
184 \
185 { \
186 register long __s0 asm ("$16") __attribute__ ((unused)) \
187 = (number); \
188 register long __v0 asm ("$2"); \
189 register long __a0 asm ("$4") = (long) (arg1); \
190 register long __a1 asm ("$5") = (long) (arg2); \
191 register long __a2 asm ("$6") = (long) (arg3); \
192 register long __a3 asm ("$7"); \
193 __asm__ volatile ( \
194 ".set\tnoreorder\n\t" \
195 v0_init \
196 "syscall\n\t" \
197 ".set\treorder" \
198 : "=r" (__v0), "=r" (__a3) \
199 : input, "r" (__a0), "r" (__a1), "r" (__a2) \
200 : __SYSCALL_CLOBBERS); \
201 err = __a3; \
202 _sys_result = __v0; \
203 } \
204 _sys_result; \
205 })
206
207 #define internal_syscall4(v0_init, input, number, err, \
208 arg1, arg2, arg3, arg4) \
209 ({ \
210 long _sys_result; \
211 \
212 { \
213 register long __s0 asm ("$16") __attribute__ ((unused)) \
214 = (number); \
215 register long __v0 asm ("$2"); \
216 register long __a0 asm ("$4") = (long) (arg1); \
217 register long __a1 asm ("$5") = (long) (arg2); \
218 register long __a2 asm ("$6") = (long) (arg3); \
219 register long __a3 asm ("$7") = (long) (arg4); \
220 __asm__ volatile ( \
221 ".set\tnoreorder\n\t" \
222 v0_init \
223 "syscall\n\t" \
224 ".set\treorder" \
225 : "=r" (__v0), "+r" (__a3) \
226 : input, "r" (__a0), "r" (__a1), "r" (__a2) \
227 : __SYSCALL_CLOBBERS); \
228 err = __a3; \
229 _sys_result = __v0; \
230 } \
231 _sys_result; \
232 })
233
234 #define internal_syscall5(v0_init, input, number, err, \
235 arg1, arg2, arg3, arg4, arg5) \
236 ({ \
237 long _sys_result; \
238 \
239 { \
240 register long __s0 asm ("$16") __attribute__ ((unused)) \
241 = (number); \
242 register long __v0 asm ("$2"); \
243 register long __a0 asm ("$4") = (long) (arg1); \
244 register long __a1 asm ("$5") = (long) (arg2); \
245 register long __a2 asm ("$6") = (long) (arg3); \
246 register long __a3 asm ("$7") = (long) (arg4); \
247 register long __a4 asm ("$8") = (long) (arg5); \
248 __asm__ volatile ( \
249 ".set\tnoreorder\n\t" \
250 v0_init \
251 "syscall\n\t" \
252 ".set\treorder" \
253 : "=r" (__v0), "+r" (__a3) \
254 : input, "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a4) \
255 : __SYSCALL_CLOBBERS); \
256 err = __a3; \
257 _sys_result = __v0; \
258 } \
259 _sys_result; \
260 })
261
262 #define internal_syscall6(v0_init, input, number, err, \
263 arg1, arg2, arg3, arg4, arg5, arg6) \
264 ({ \
265 long _sys_result; \
266 \
267 { \
268 register long __s0 asm ("$16") __attribute__ ((unused)) \
269 = (number); \
270 register long __v0 asm ("$2"); \
271 register long __a0 asm ("$4") = (long) (arg1); \
272 register long __a1 asm ("$5") = (long) (arg2); \
273 register long __a2 asm ("$6") = (long) (arg3); \
274 register long __a3 asm ("$7") = (long) (arg4); \
275 register long __a4 asm ("$8") = (long) (arg5); \
276 register long __a5 asm ("$9") = (long) (arg6); \
277 __asm__ volatile ( \
278 ".set\tnoreorder\n\t" \
279 v0_init \
280 "syscall\n\t" \
281 ".set\treorder" \
282 : "=r" (__v0), "+r" (__a3) \
283 : input, "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a4), \
284 "r" (__a5) \
285 : __SYSCALL_CLOBBERS); \
286 err = __a3; \
287 _sys_result = __v0; \
288 } \
289 _sys_result; \
290 })
291
292 #define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
293 "$14", "$15", "$24", "$25", "hi", "lo", "memory"
294
295 /* Standard MIPS syscalls have an error flag, and return a positive errno
296 when the error flag is set. Emulate this behaviour for vsyscalls so that
297 the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly. */
298 #define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
299 ({ \
300 long _ret = funcptr (args); \
301 err = ((unsigned long) (_ret) >= (unsigned long) -4095L); \
302 if (err) \
303 _ret = -_ret; \
304 _ret; \
305 })
306
307 /* List of system calls which are supported as vsyscalls. */
308 #define HAVE_CLOCK_GETTIME_VSYSCALL 1
309 #define HAVE_GETTIMEOFDAY_VSYSCALL 1
310
311 #endif /* __ASSEMBLER__ */
312
313 /* Pointer mangling is not yet supported for MIPS. */
314 #define PTR_MANGLE(var) (void) (var)
315 #define PTR_DEMANGLE(var) (void) (var)
316
317 #endif /* linux/mips/sysdep.h */