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