master
1/* Copyright (C) 2000-2025 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_MIPS32_SYSDEP_H
19#define _LINUX_MIPS_MIPS32_SYSDEP_H 1
20
21/* mips32 have cancelable syscalls with 7 arguments (currently only
22 sync_file_range). */
23#define HAVE_CANCELABLE_SYSCALL_WITH_7_ARGS 1
24
25/* There is some commonality. */
26#include <sysdeps/unix/sysv/linux/mips/sysdep.h>
27#include <sysdeps/unix/sysv/linux/sysdep.h>
28#include <sysdeps/unix/mips/mips32/sysdep.h>
29
30#include <tls.h>
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#ifdef __PIC__
44# undef SYSCALL_ERROR_LABEL
45# define SYSCALL_ERROR_LABEL 99b
46#endif
47
48#else /* ! __ASSEMBLER__ */
49
50#undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
51#define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
52
53/* Note that the original Linux syscall restart convention required the
54 instruction immediately preceding SYSCALL to initialize $v0 with the
55 syscall number. Then if a restart triggered, $v0 would have been
56 clobbered by the syscall interrupted, and needed to be reinititalized.
57 The kernel would decrement the PC by 4 before switching back to the
58 user mode so that $v0 had been reloaded before SYSCALL was executed
59 again. This implied the place $v0 was loaded from must have been
60 preserved across a syscall, e.g. an immediate, static register, stack
61 slot, etc.
62
63 The convention was relaxed in Linux with a change applied to the kernel
64 GIT repository as commit 96187fb0bc30cd7919759d371d810e928048249d, that
65 first appeared in the 2.6.36 release. Since then the kernel has had
66 code that reloads $v0 upon syscall restart and resumes right at the
67 SYSCALL instruction, so no special arrangement is needed anymore.
68
69 For backwards compatibility with existing kernel binaries we support
70 the old convention by choosing the instruction preceding SYSCALL
71 carefully. This also means we have to force a 32-bit encoding of the
72 microMIPS MOVE instruction if one is used. */
73
74#ifdef __mips_micromips
75# define MOVE32 "move32"
76#else
77# define MOVE32 "move"
78#endif
79
80#undef INTERNAL_SYSCALL
81#undef INTERNAL_SYSCALL_NCS
82
83#define __nomips16 __attribute__ ((nomips16))
84
85union __mips_syscall_return
86 {
87 long long int val;
88 struct
89 {
90 long int v0;
91 long int v1;
92 }
93 reg;
94 };
95
96#ifdef __mips16
97/* There's no MIPS16 syscall instruction, so we go through out-of-line
98 standard MIPS wrappers. These do use inline snippets below though,
99 through INTERNAL_SYSCALL_MIPS16. Spilling the syscall number to
100 memory gives the best code in that case, avoiding the need to save
101 and restore a static register. */
102
103# include <mips16-syscall.h>
104
105# define INTERNAL_SYSCALL(name, nr, args...) \
106 INTERNAL_SYSCALL_NCS (SYS_ify (name), nr, args)
107
108# define INTERNAL_SYSCALL_NCS(number, nr, args...) \
109({ \
110 union __mips_syscall_return _sc_ret; \
111 _sc_ret.val = __mips16_syscall##nr (args, number); \
112 _sc_ret.reg.v0; \
113})
114
115# define INTERNAL_SYSCALL_MIPS16(number, err, nr, args...) \
116 internal_syscall##nr ("lw\t%0, %2\n\t", \
117 "R" (number), \
118 number, err, args)
119
120#else /* !__mips16 */
121# define INTERNAL_SYSCALL(name, nr, args...) \
122 internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t", \
123 "IK" (SYS_ify (name)), \
124 SYS_ify (name), err, args)
125
126# define INTERNAL_SYSCALL_NCS(number, nr, args...) \
127 internal_syscall##nr (MOVE32 "\t%0, %2\n\t", \
128 "r" (__s0), \
129 number, err, args)
130
131#endif /* !__mips16 */
132
133#define internal_syscall0(v0_init, input, number, err, dummy...) \
134({ \
135 long int _sys_result; \
136 \
137 { \
138 register long int __s0 asm ("$16") __attribute__ ((unused)) \
139 = (number); \
140 register long int __v0 asm ("$2"); \
141 register long int __a3 asm ("$7"); \
142 __asm__ volatile ( \
143 ".set\tnoreorder\n\t" \
144 v0_init \
145 "syscall\n\t" \
146 ".set reorder" \
147 : "=r" (__v0), "=r" (__a3) \
148 : input \
149 : __SYSCALL_CLOBBERS); \
150 _sys_result = __a3 != 0 ? -__v0 : __v0; \
151 } \
152 _sys_result; \
153})
154
155#define internal_syscall1(v0_init, input, number, err, arg1) \
156({ \
157 long int _sys_result; \
158 \
159 { \
160 long int _arg1 = (long int) (arg1); \
161 register long int __s0 asm ("$16") __attribute__ ((unused)) \
162 = (number); \
163 register long int __v0 asm ("$2"); \
164 register long int __a0 asm ("$4") = _arg1; \
165 register long int __a3 asm ("$7"); \
166 __asm__ volatile ( \
167 ".set\tnoreorder\n\t" \
168 v0_init \
169 "syscall\n\t" \
170 ".set reorder" \
171 : "=r" (__v0), "=r" (__a3) \
172 : input, "r" (__a0) \
173 : __SYSCALL_CLOBBERS); \
174 _sys_result = __a3 != 0 ? -__v0 : __v0; \
175 } \
176 _sys_result; \
177})
178
179#define internal_syscall2(v0_init, input, number, err, arg1, arg2) \
180({ \
181 long int _sys_result; \
182 \
183 { \
184 long int _arg1 = (long int) (arg1); \
185 long int _arg2 = (long int) (arg2); \
186 register long int __s0 asm ("$16") __attribute__ ((unused)) \
187 = (number); \
188 register long int __v0 asm ("$2"); \
189 register long int __a0 asm ("$4") = _arg1; \
190 register long int __a1 asm ("$5") = _arg2; \
191 register long int __a3 asm ("$7"); \
192 __asm__ volatile ( \
193 ".set\tnoreorder\n\t" \
194 v0_init \
195 "syscall\n\t" \
196 ".set\treorder" \
197 : "=r" (__v0), "=r" (__a3) \
198 : input, "r" (__a0), "r" (__a1) \
199 : __SYSCALL_CLOBBERS); \
200 _sys_result = __a3 != 0 ? -__v0 : __v0; \
201 } \
202 _sys_result; \
203})
204
205#define internal_syscall3(v0_init, input, number, err, \
206 arg1, arg2, arg3) \
207({ \
208 long int _sys_result; \
209 \
210 { \
211 long int _arg1 = (long int) (arg1); \
212 long int _arg2 = (long int) (arg2); \
213 long int _arg3 = (long int) (arg3); \
214 register long int __s0 asm ("$16") __attribute__ ((unused)) \
215 = (number); \
216 register long int __v0 asm ("$2"); \
217 register long int __a0 asm ("$4") = _arg1; \
218 register long int __a1 asm ("$5") = _arg2; \
219 register long int __a2 asm ("$6") = _arg3; \
220 register long int __a3 asm ("$7"); \
221 __asm__ volatile ( \
222 ".set\tnoreorder\n\t" \
223 v0_init \
224 "syscall\n\t" \
225 ".set\treorder" \
226 : "=r" (__v0), "=r" (__a3) \
227 : input, "r" (__a0), "r" (__a1), "r" (__a2) \
228 : __SYSCALL_CLOBBERS); \
229 _sys_result = __a3 != 0 ? -__v0 : __v0; \
230 } \
231 _sys_result; \
232})
233
234#define internal_syscall4(v0_init, input, number, err, \
235 arg1, arg2, arg3, arg4) \
236({ \
237 long int _sys_result; \
238 \
239 { \
240 long int _arg1 = (long int) (arg1); \
241 long int _arg2 = (long int) (arg2); \
242 long int _arg3 = (long int) (arg3); \
243 long int _arg4 = (long int) (arg4); \
244 register long int __s0 asm ("$16") __attribute__ ((unused)) \
245 = (number); \
246 register long int __v0 asm ("$2"); \
247 register long int __a0 asm ("$4") = _arg1; \
248 register long int __a1 asm ("$5") = _arg2; \
249 register long int __a2 asm ("$6") = _arg3; \
250 register long int __a3 asm ("$7") = _arg4; \
251 __asm__ volatile ( \
252 ".set\tnoreorder\n\t" \
253 v0_init \
254 "syscall\n\t" \
255 ".set\treorder" \
256 : "=r" (__v0), "+r" (__a3) \
257 : input, "r" (__a0), "r" (__a1), "r" (__a2) \
258 : __SYSCALL_CLOBBERS); \
259 _sys_result = __a3 != 0 ? -__v0 : __v0; \
260 } \
261 _sys_result; \
262})
263
264/* Standalone MIPS wrappers used for 5, 6, and 7 argument syscalls,
265 which require stack arguments. We rely on the compiler arranging
266 wrapper's arguments according to the MIPS o32 function calling
267 convention, which is reused by syscalls, except for the syscall
268 number passed and the error flag returned (taken care of in the
269 wrapper called). This relieves us from relying on non-guaranteed
270 compiler specifics required for the stack arguments to be pushed,
271 which would be the case if these syscalls were inlined. */
272
273long long int __nomips16 __mips_syscall5 (long int arg1, long int arg2,
274 long int arg3, long int arg4,
275 long int arg5,
276 long int number);
277libc_hidden_proto (__mips_syscall5, nomips16)
278
279#define internal_syscall5(v0_init, input, number, err, \
280 arg1, arg2, arg3, arg4, arg5) \
281({ \
282 union __mips_syscall_return _sc_ret; \
283 _sc_ret.val = __mips_syscall5 ((long int) (arg1), \
284 (long int) (arg2), \
285 (long int) (arg3), \
286 (long int) (arg4), \
287 (long int) (arg5), \
288 (long int) (number)); \
289 _sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0; \
290})
291
292long long int __nomips16 __mips_syscall6 (long int arg1, long int arg2,
293 long int arg3, long int arg4,
294 long int arg5, long int arg6,
295 long int number);
296libc_hidden_proto (__mips_syscall6, nomips16)
297
298#define internal_syscall6(v0_init, input, number, err, \
299 arg1, arg2, arg3, arg4, arg5, arg6) \
300({ \
301 union __mips_syscall_return _sc_ret; \
302 _sc_ret.val = __mips_syscall6 ((long int) (arg1), \
303 (long int) (arg2), \
304 (long int) (arg3), \
305 (long int) (arg4), \
306 (long int) (arg5), \
307 (long int) (arg6), \
308 (long int) (number)); \
309 _sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0; \
310})
311
312long long int __nomips16 __mips_syscall7 (long int arg1, long int arg2,
313 long int arg3, long int arg4,
314 long int arg5, long int arg6,
315 long int arg7,
316 long int number);
317libc_hidden_proto (__mips_syscall7, nomips16)
318
319#define internal_syscall7(v0_init, input, number, err, \
320 arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
321({ \
322 union __mips_syscall_return _sc_ret; \
323 _sc_ret.val = __mips_syscall7 ((long int) (arg1), \
324 (long int) (arg2), \
325 (long int) (arg3), \
326 (long int) (arg4), \
327 (long int) (arg5), \
328 (long int) (arg6), \
329 (long int) (arg7), \
330 (long int) (number)); \
331 _sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0; \
332})
333
334#if __mips_isa_rev >= 6
335# define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
336 "$14", "$15", "$24", "$25", "memory"
337#else
338# define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
339 "$14", "$15", "$24", "$25", "hi", "lo", "memory"
340#endif
341
342#endif /* __ASSEMBLER__ */
343
344#endif /* linux/mips/mips32/sysdep.h */