1 /* Copyright (C) 2000-2021 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 /* 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/mips32/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 #ifdef __PIC__
40 # undef SYSCALL_ERROR_LABEL
41 # define SYSCALL_ERROR_LABEL 99b
42 #endif
43 
44 #else   /* ! __ASSEMBLER__ */
45 
46 #undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
47 #define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
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 #undef INTERNAL_SYSCALL_NCS
78 
79 #define __nomips16 __attribute__ ((nomips16))
80 
81 union __mips_syscall_return
82   {
83     long long int val;
84     struct
85       {
86 	long int v0;
87 	long int v1;
88       }
89     reg;
90   };
91 
92 #ifdef __mips16
93 /* There's no MIPS16 syscall instruction, so we go through out-of-line
94    standard MIPS wrappers.  These do use inline snippets below though,
95    through INTERNAL_SYSCALL_MIPS16.  Spilling the syscall number to
96    memory gives the best code in that case, avoiding the need to save
97    and restore a static register.  */
98 
99 # include <mips16-syscall.h>
100 
101 # define INTERNAL_SYSCALL(name, nr, args...)				\
102 	INTERNAL_SYSCALL_NCS (SYS_ify (name), nr, args)
103 
104 # define INTERNAL_SYSCALL_NCS(number, nr, args...)			\
105 ({									\
106 	union __mips_syscall_return _sc_ret;				\
107 	_sc_ret.val = __mips16_syscall##nr (args, number);		\
108 	_sc_ret.reg.v0;							\
109 })
110 
111 # define INTERNAL_SYSCALL_MIPS16(number, err, nr, args...)		\
112 	internal_syscall##nr ("lw\t%0, %2\n\t",				\
113 			      "R" (number),				\
114 			      number, err, args)
115 
116 #else /* !__mips16 */
117 # define INTERNAL_SYSCALL(name, nr, args...)				\
118 	internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t",	\
119 			      "IK" (SYS_ify (name)),			\
120 			      SYS_ify (name), err, args)
121 
122 # define INTERNAL_SYSCALL_NCS(number, nr, args...)			\
123 	internal_syscall##nr (MOVE32 "\t%0, %2\n\t",			\
124 			      "r" (__s0),				\
125 			      number, err, args)
126 
127 #endif /* !__mips16 */
128 
129 #define internal_syscall0(v0_init, input, number, err, dummy...)	\
130 ({									\
131 	long int _sys_result;						\
132 									\
133 	{								\
134 	register long int __s0 asm ("$16") __attribute__ ((unused))	\
135 	  = (number);							\
136 	register long int __v0 asm ("$2");				\
137 	register long int __a3 asm ("$7");				\
138 	__asm__ volatile (						\
139 	".set\tnoreorder\n\t"						\
140 	v0_init								\
141 	"syscall\n\t"							\
142 	".set reorder"							\
143 	: "=r" (__v0), "=r" (__a3)					\
144 	: input								\
145 	: __SYSCALL_CLOBBERS);						\
146 	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
147 	}								\
148 	_sys_result;							\
149 })
150 
151 #define internal_syscall1(v0_init, input, number, err, arg1)		\
152 ({									\
153 	long int _sys_result;						\
154 									\
155 	{								\
156 	long int _arg1 = (long int) (arg1);				\
157 	register long int __s0 asm ("$16") __attribute__ ((unused))	\
158 	  = (number);							\
159 	register long int __v0 asm ("$2");				\
160 	register long int __a0 asm ("$4") = _arg1;			\
161 	register long int __a3 asm ("$7");				\
162 	__asm__ volatile (						\
163 	".set\tnoreorder\n\t"						\
164 	v0_init								\
165 	"syscall\n\t"							\
166 	".set reorder"							\
167 	: "=r" (__v0), "=r" (__a3)					\
168 	: input, "r" (__a0)						\
169 	: __SYSCALL_CLOBBERS);						\
170 	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
171 	}								\
172 	_sys_result;							\
173 })
174 
175 #define internal_syscall2(v0_init, input, number, err, arg1, arg2)	\
176 ({									\
177 	long int _sys_result;						\
178 									\
179 	{								\
180 	long int _arg1 = (long int) (arg1);				\
181 	long int _arg2 = (long int) (arg2);				\
182 	register long int __s0 asm ("$16") __attribute__ ((unused))	\
183 	  = (number);							\
184 	register long int __v0 asm ("$2");				\
185 	register long int __a0 asm ("$4") = _arg1;			\
186 	register long int __a1 asm ("$5") = _arg2;			\
187 	register long int __a3 asm ("$7");				\
188 	__asm__ volatile (						\
189 	".set\tnoreorder\n\t"						\
190 	v0_init								\
191 	"syscall\n\t"							\
192 	".set\treorder"							\
193 	: "=r" (__v0), "=r" (__a3)					\
194 	: input, "r" (__a0), "r" (__a1)					\
195 	: __SYSCALL_CLOBBERS);						\
196 	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
197 	}								\
198 	_sys_result;							\
199 })
200 
201 #define internal_syscall3(v0_init, input, number, err,			\
202 			  arg1, arg2, arg3)				\
203 ({									\
204 	long int _sys_result;						\
205 									\
206 	{								\
207 	long int _arg1 = (long int) (arg1);				\
208 	long int _arg2 = (long int) (arg2);				\
209 	long int _arg3 = (long int) (arg3);				\
210 	register long int __s0 asm ("$16") __attribute__ ((unused))	\
211 	  = (number);							\
212 	register long int __v0 asm ("$2");				\
213 	register long int __a0 asm ("$4") = _arg1;			\
214 	register long int __a1 asm ("$5") = _arg2;			\
215 	register long int __a2 asm ("$6") = _arg3;			\
216 	register long int __a3 asm ("$7");				\
217 	__asm__ volatile (						\
218 	".set\tnoreorder\n\t"						\
219 	v0_init								\
220 	"syscall\n\t"							\
221 	".set\treorder"							\
222 	: "=r" (__v0), "=r" (__a3)					\
223 	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\
224 	: __SYSCALL_CLOBBERS);						\
225 	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
226 	}								\
227 	_sys_result;							\
228 })
229 
230 #define internal_syscall4(v0_init, input, number, err,			\
231 			  arg1, arg2, arg3, arg4)			\
232 ({									\
233 	long int _sys_result;						\
234 									\
235 	{								\
236 	long int _arg1 = (long int) (arg1);				\
237 	long int _arg2 = (long int) (arg2);				\
238 	long int _arg3 = (long int) (arg3);				\
239 	long int _arg4 = (long int) (arg4);				\
240 	register long int __s0 asm ("$16") __attribute__ ((unused))	\
241 	  = (number);							\
242 	register long int __v0 asm ("$2");				\
243 	register long int __a0 asm ("$4") = _arg1;			\
244 	register long int __a1 asm ("$5") = _arg2;			\
245 	register long int __a2 asm ("$6") = _arg3;			\
246 	register long int __a3 asm ("$7") = _arg4;			\
247 	__asm__ volatile (						\
248 	".set\tnoreorder\n\t"						\
249 	v0_init								\
250 	"syscall\n\t"							\
251 	".set\treorder"							\
252 	: "=r" (__v0), "+r" (__a3)					\
253 	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\
254 	: __SYSCALL_CLOBBERS);						\
255 	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
256 	}								\
257 	_sys_result;							\
258 })
259 
260 /* Standalone MIPS wrappers used for 5, 6, and 7 argument syscalls,
261    which require stack arguments.  We rely on the compiler arranging
262    wrapper's arguments according to the MIPS o32 function calling
263    convention, which is reused by syscalls, except for the syscall
264    number passed and the error flag returned (taken care of in the
265    wrapper called).  This relieves us from relying on non-guaranteed
266    compiler specifics required for the stack arguments to be pushed,
267    which would be the case if these syscalls were inlined.  */
268 
269 long long int __nomips16 __mips_syscall5 (long int arg1, long int arg2,
270 					  long int arg3, long int arg4,
271 					  long int arg5,
272 					  long int number);
273 libc_hidden_proto (__mips_syscall5, nomips16)
274 
275 #define internal_syscall5(v0_init, input, number, err,			\
276 			  arg1, arg2, arg3, arg4, arg5)			\
277 ({									\
278 	union __mips_syscall_return _sc_ret;				\
279 	_sc_ret.val = __mips_syscall5 ((long int) (arg1),		\
280 				       (long int) (arg2),		\
281 				       (long int) (arg3),		\
282 				       (long int) (arg4),		\
283 				       (long int) (arg5),		\
284 				       (long int) (number));		\
285 	_sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0;		\
286 })
287 
288 long long int __nomips16 __mips_syscall6 (long int arg1, long int arg2,
289 					  long int arg3, long int arg4,
290 					  long int arg5, long int arg6,
291 					  long int number);
292 libc_hidden_proto (__mips_syscall6, nomips16)
293 
294 #define internal_syscall6(v0_init, input, number, err,			\
295 			  arg1, arg2, arg3, arg4, arg5, arg6)		\
296 ({									\
297 	union __mips_syscall_return _sc_ret;				\
298 	_sc_ret.val = __mips_syscall6 ((long int) (arg1),		\
299 				       (long int) (arg2),		\
300 				       (long int) (arg3),		\
301 				       (long int) (arg4),		\
302 				       (long int) (arg5),		\
303 				       (long int) (arg6),		\
304 				       (long int) (number));		\
305 	_sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0;		\
306 })
307 
308 long long int __nomips16 __mips_syscall7 (long int arg1, long int arg2,
309 					  long int arg3, long int arg4,
310 					  long int arg5, long int arg6,
311 					  long int arg7,
312 					  long int number);
313 libc_hidden_proto (__mips_syscall7, nomips16)
314 
315 #define internal_syscall7(v0_init, input, number, err,			\
316 			  arg1, arg2, arg3, arg4, arg5, arg6, arg7)	\
317 ({									\
318 	union __mips_syscall_return _sc_ret;				\
319 	_sc_ret.val = __mips_syscall7 ((long int) (arg1),		\
320 				       (long int) (arg2),		\
321 				       (long int) (arg3),		\
322 				       (long int) (arg4),		\
323 				       (long int) (arg5),		\
324 				       (long int) (arg6),		\
325 				       (long int) (arg7),		\
326 				       (long int) (number));		\
327 	_sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0;		\
328 })
329 
330 #if __mips_isa_rev >= 6
331 # define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
332 	 "$14", "$15", "$24", "$25", "memory"
333 #else
334 # define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
335 	 "$14", "$15", "$24", "$25", "hi", "lo", "memory"
336 #endif
337 
338 #endif /* __ASSEMBLER__ */
339 
340 /* Pointer mangling is not yet supported for MIPS.  */
341 #define PTR_MANGLE(var) (void) (var)
342 #define PTR_DEMANGLE(var) (void) (var)
343 
344 #endif /* linux/mips/mips32/sysdep.h */
345