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 */