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