master
  1/* Assembly macros for RISC-V.
  2   Copyright (C) 2011-2018
  3   This file is part of the GNU C Library.
  4
  5   The GNU C Library is free software; you can redistribute it and/or
  6   modify it under the terms of the GNU Lesser General Public
  7   License as published by the Free Software Foundation; either
  8   version 2.1 of the License, or (at your option) any later version.
  9
 10   The GNU C Library is distributed in the hope that it will be useful,
 11   but WITHOUT ANY WARRANTY; without even the implied warranty of
 12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13   Lesser General Public License for more details.
 14
 15   You should have received a copy of the GNU Lesser General Public
 16   License along with the GNU C Library.  If not, see
 17   <https://www.gnu.org/licenses/>.  */
 18
 19#ifndef _LINUX_RISCV_SYSDEP_H
 20#define _LINUX_RISCV_SYSDEP_H 1
 21
 22#include <sysdeps/unix/sysv/linux/sysdep.h>
 23#include <sysdeps/unix/sysdep.h>
 24#include <tls.h>
 25
 26#undef SYS_ify
 27#define SYS_ify(syscall_name)	__NR_##syscall_name
 28
 29#if __WORDSIZE == 32
 30
 31/* Workarounds for generic code needing to handle 64-bit time_t.  */
 32
 33/* Fix sysdeps/unix/sysv/linux/clock_getcpuclockid.c.  */
 34#define __NR_clock_getres	__NR_clock_getres_time64
 35/* Fix sysdeps/nptl/lowlevellock-futex.h.  */
 36#define __NR_futex		__NR_futex_time64
 37/* Fix sysdeps/unix/sysv/linux/pause.c.  */
 38#define __NR_ppoll		__NR_ppoll_time64
 39/* Fix sysdeps/unix/sysv/linux/select.c.  */
 40#define __NR_pselect6		__NR_pselect6_time64
 41/* Fix sysdeps/unix/sysv/linux/recvmmsg.c.  */
 42#define __NR_recvmmsg		__NR_recvmmsg_time64
 43/* Fix sysdeps/unix/sysv/linux/sigtimedwait.c.  */
 44#define __NR_rt_sigtimedwait	__NR_rt_sigtimedwait_time64
 45/* Fix sysdeps/unix/sysv/linux/semtimedop.c.  */
 46#define __NR_semtimedop		__NR_semtimedop_time64
 47/* Hack sysdeps/unix/sysv/linux/generic/utimes.c.  */
 48#define __NR_utimensat		__NR_utimensat_time64
 49
 50#endif /* __WORDSIZE == 32 */
 51
 52#ifdef __ASSEMBLER__
 53
 54# include <sys/asm.h>
 55
 56# define ENTRY(name) LEAF(name)
 57
 58# define L(label) .L ## label
 59
 60/* Performs a system call, handling errors by setting errno.  Linux indicates
 61   errors by setting a0 to a value between -1 and -4095.  */
 62# undef PSEUDO
 63# define PSEUDO(name, syscall_name, args)			\
 64  .text;							\
 65  .align 2;							\
 66  ENTRY (name);							\
 67  li a7, SYS_ify (syscall_name);				\
 68  scall;							\
 69  li a7, -4096;							\
 70  bgtu a0, a7, .Lsyscall_error ## name;
 71
 72# undef PSEUDO_END
 73# define PSEUDO_END(sym) 					\
 74  SYSCALL_ERROR_HANDLER (sym)					\
 75  ret;								\
 76  END (sym)
 77
 78# if !IS_IN (libc)
 79#  if RTLD_PRIVATE_ERRNO
 80#   define SYSCALL_ERROR_HANDLER(name)				\
 81.Lsyscall_error ## name:					\
 82	li t1, -4096;						\
 83	neg a0, a0;						\
 84        sw a0, rtld_errno, t1;					\
 85        li a0, -1;
 86#  elif defined (__PIC__)
 87#   define SYSCALL_ERROR_HANDLER(name)				\
 88.Lsyscall_error ## name:					\
 89        la.tls.ie t1, errno;					\
 90	add t1, t1, tp;						\
 91	neg a0, a0;						\
 92	sw a0, 0(t1);						\
 93        li a0, -1;
 94#  else
 95#   define SYSCALL_ERROR_HANDLER(name)				\
 96.Lsyscall_error ## name:					\
 97        lui t1, %tprel_hi(errno);				\
 98        add t1, t1, tp, %tprel_add(errno);			\
 99	neg a0, a0;						\
100        sw a0, %tprel_lo(errno)(t1);				\
101        li a0, -1;
102#  endif
103# else
104#  define SYSCALL_ERROR_HANDLER(name)				\
105.Lsyscall_error ## name:					\
106        tail    __syscall_error;
107# endif
108
109/* Performs a system call, not setting errno.  */
110# undef PSEUDO_NEORRNO
111# define PSEUDO_NOERRNO(name, syscall_name, args)	\
112  .align 2;						\
113  ENTRY (name);						\
114  li a7, SYS_ify (syscall_name);			\
115  scall;
116
117# undef PSEUDO_END_NOERRNO
118# define PSEUDO_END_NOERRNO(name)			\
119  END (name)
120
121# undef ret_NOERRNO
122# define ret_NOERRNO ret
123
124/* Performs a system call, returning the error code.  */
125# undef PSEUDO_ERRVAL
126# define PSEUDO_ERRVAL(name, syscall_name, args) 	\
127  PSEUDO_NOERRNO (name, syscall_name, args)		\
128  neg a0, a0;
129
130# undef PSEUDO_END_ERRVAL
131# define PSEUDO_END_ERRVAL(name)			\
132  END (name)
133
134# undef ret_ERRVAL
135# define ret_ERRVAL ret
136
137#else /* !__ASSEMBLER__ */
138
139# if __WORDSIZE == 64
140#  define VDSO_NAME	"LINUX_4.15"
141#  define VDSO_HASH	182943605
142
143/* List of system calls which are supported as vsyscalls only
144   for RV64.  */
145#  define HAVE_CLOCK_GETRES64_VSYSCALL	"__vdso_clock_getres"
146#  define HAVE_CLOCK_GETTIME64_VSYSCALL	"__vdso_clock_gettime"
147#  define HAVE_GETTIMEOFDAY_VSYSCALL	"__vdso_gettimeofday"
148#  define HAVE_GETRANDOM_VSYSCALL	"__vdso_getrandom"
149# else
150#  define VDSO_NAME	"LINUX_5.4"
151#  define VDSO_HASH	61765876
152
153/* RV32 does not support the gettime and getrandom VDSO syscalls.  */
154# endif
155# define HAVE_CLONE3_WRAPPER		1
156
157/* List of system calls which are supported as vsyscalls (for RV32 and
158   RV64).  */
159# define HAVE_GETCPU_VSYSCALL		"__vdso_getcpu"
160# define HAVE_RISCV_HWPROBE		"__vdso_riscv_hwprobe"
161
162# undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
163# define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
164
165# define INTERNAL_SYSCALL(name, nr, args...) \
166	internal_syscall##nr (SYS_ify (name), args)
167
168# define INTERNAL_SYSCALL_NCS(number, nr, args...) \
169	internal_syscall##nr (number, args)
170
171# define internal_syscall0(number, dummy...)			\
172({ 									\
173	long int _sys_result;						\
174									\
175	{								\
176	register long int __a7 asm ("a7") = number;			\
177	register long int __a0 asm ("a0");				\
178	__asm__ volatile ( 						\
179	"scall\n\t" 							\
180	: "=r" (__a0)							\
181	: "r" (__a7)							\
182	: __SYSCALL_CLOBBERS); 						\
183	_sys_result = __a0;						\
184	}								\
185	_sys_result;							\
186})
187
188# define internal_syscall1(number, arg0)				\
189({ 									\
190	long int _sys_result;						\
191	long int _arg0 = (long int) (arg0);				\
192									\
193	{								\
194	register long int __a7 asm ("a7") = number;			\
195	register long int __a0 asm ("a0") = _arg0;			\
196	__asm__ volatile ( 						\
197	"scall\n\t" 							\
198	: "+r" (__a0)							\
199	: "r" (__a7)							\
200	: __SYSCALL_CLOBBERS); 						\
201	_sys_result = __a0;						\
202	}								\
203	_sys_result;							\
204})
205
206# define internal_syscall2(number, arg0, arg1)	    		\
207({ 									\
208	long int _sys_result;						\
209	long int _arg0 = (long int) (arg0);				\
210	long int _arg1 = (long int) (arg1);				\
211									\
212	{								\
213	register long int __a7 asm ("a7") = number;			\
214	register long int __a0 asm ("a0") = _arg0;			\
215	register long int __a1 asm ("a1") = _arg1;			\
216	__asm__ volatile ( 						\
217	"scall\n\t" 							\
218	: "+r" (__a0)							\
219	: "r" (__a7), "r" (__a1)					\
220	: __SYSCALL_CLOBBERS); 						\
221	_sys_result = __a0;						\
222	}								\
223	_sys_result;							\
224})
225
226# define internal_syscall3(number, arg0, arg1, arg2)      		\
227({ 									\
228	long int _sys_result;						\
229	long int _arg0 = (long int) (arg0);				\
230	long int _arg1 = (long int) (arg1);				\
231	long int _arg2 = (long int) (arg2);				\
232									\
233	{								\
234	register long int __a7 asm ("a7") = number;			\
235	register long int __a0 asm ("a0") = _arg0;			\
236	register long int __a1 asm ("a1") = _arg1;			\
237	register long int __a2 asm ("a2") = _arg2;			\
238	__asm__ volatile ( 						\
239	"scall\n\t" 							\
240	: "+r" (__a0)							\
241	: "r" (__a7), "r" (__a1), "r" (__a2)				\
242	: __SYSCALL_CLOBBERS); 						\
243	_sys_result = __a0;						\
244	}								\
245	_sys_result;							\
246})
247
248# define internal_syscall4(number, arg0, arg1, arg2, arg3)	  \
249({ 									\
250	long int _sys_result;						\
251	long int _arg0 = (long int) (arg0);				\
252	long int _arg1 = (long int) (arg1);				\
253	long int _arg2 = (long int) (arg2);				\
254	long int _arg3 = (long int) (arg3);				\
255									\
256	{								\
257	register long int __a7 asm ("a7") = number;			\
258	register long int __a0 asm ("a0") = _arg0;			\
259	register long int __a1 asm ("a1") = _arg1;			\
260	register long int __a2 asm ("a2") = _arg2;			\
261	register long int __a3 asm ("a3") = _arg3;			\
262	__asm__ volatile ( 						\
263	"scall\n\t" 							\
264	: "+r" (__a0)							\
265	: "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3)		\
266	: __SYSCALL_CLOBBERS); 						\
267	_sys_result = __a0;						\
268	}								\
269	_sys_result;							\
270})
271
272# define internal_syscall5(number, arg0, arg1, arg2, arg3, arg4)   \
273({ 									\
274	long int _sys_result;						\
275	long int _arg0 = (long int) (arg0);				\
276	long int _arg1 = (long int) (arg1);				\
277	long int _arg2 = (long int) (arg2);				\
278	long int _arg3 = (long int) (arg3);				\
279	long int _arg4 = (long int) (arg4);				\
280									\
281	{								\
282	register long int __a7 asm ("a7") = number;			\
283	register long int __a0 asm ("a0") = _arg0;			\
284	register long int __a1 asm ("a1") = _arg1;			\
285	register long int __a2 asm ("a2") = _arg2;			\
286	register long int __a3 asm ("a3") = _arg3;			\
287	register long int __a4 asm ("a4") = _arg4;			\
288	__asm__ volatile ( 						\
289	"scall\n\t" 							\
290	: "+r" (__a0)							\
291	: "r" (__a7), "r"(__a1), "r"(__a2), "r"(__a3), "r" (__a4)	\
292	: __SYSCALL_CLOBBERS); 						\
293	_sys_result = __a0;						\
294	}								\
295	_sys_result;							\
296})
297
298# define internal_syscall6(number, arg0, arg1, arg2, arg3, arg4, arg5) \
299({ 									\
300	long int _sys_result;						\
301	long int _arg0 = (long int) (arg0);				\
302	long int _arg1 = (long int) (arg1);				\
303	long int _arg2 = (long int) (arg2);				\
304	long int _arg3 = (long int) (arg3);				\
305	long int _arg4 = (long int) (arg4);				\
306	long int _arg5 = (long int) (arg5);				\
307									\
308	{								\
309	register long int __a7 asm ("a7") = number;			\
310	register long int __a0 asm ("a0") = _arg0;			\
311	register long int __a1 asm ("a1") = _arg1;			\
312	register long int __a2 asm ("a2") = _arg2;			\
313	register long int __a3 asm ("a3") = _arg3;			\
314	register long int __a4 asm ("a4") = _arg4;			\
315	register long int __a5 asm ("a5") = _arg5;			\
316	__asm__ volatile ( 						\
317	"scall\n\t" 							\
318	: "+r" (__a0)							\
319	: "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3),		\
320	  "r" (__a4), "r" (__a5)					\
321	: __SYSCALL_CLOBBERS); 						\
322	_sys_result = __a0;						\
323	}								\
324	_sys_result;							\
325})
326
327# define internal_syscall7(number, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \
328({ 									\
329	long int _sys_result;						\
330	long int _arg0 = (long int) (arg0);				\
331	long int _arg1 = (long int) (arg1);				\
332	long int _arg2 = (long int) (arg2);				\
333	long int _arg3 = (long int) (arg3);				\
334	long int _arg4 = (long int) (arg4);				\
335	long int _arg5 = (long int) (arg5);				\
336	long int _arg6 = (long int) (arg6);				\
337									\
338	{								\
339	register long int __a7 asm ("a7") = number;			\
340	register long int __a0 asm ("a0") = _arg0;			\
341	register long int __a1 asm ("a1") = _arg1;			\
342	register long int __a2 asm ("a2") = _arg2;			\
343	register long int __a3 asm ("a3") = _arg3;			\
344	register long int __a4 asm ("a4") = _arg4;			\
345	register long int __a5 asm ("a5") = _arg5;			\
346	register long int __a6 asm ("a6") = _arg6;			\
347	__asm__ volatile ( 						\
348	"scall\n\t" 							\
349	: "+r" (__a0)							\
350	: "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3),		\
351	  "r" (__a4), "r" (__a5), "r" (__a6)				\
352	: __SYSCALL_CLOBBERS); 						\
353	_sys_result = __a0;						\
354	}								\
355	_sys_result;							\
356})
357
358# define __SYSCALL_CLOBBERS "memory"
359
360extern long int __syscall_error (long int neg_errno);
361
362#endif /* ! __ASSEMBLER__ */
363
364#endif /* linux/riscv/sysdep.h */