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