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  # else
     149  #  define VDSO_NAME	"LINUX_5.4"
     150  #  define VDSO_HASH	61765876
     151  
     152  /* RV32 does not support the gettime VDSO syscalls.  */
     153  # endif
     154  # define HAVE_CLONE3_WRAPPER		1
     155  
     156  /* List of system calls which are supported as vsyscalls (for RV32 and
     157     RV64).  */
     158  # define HAVE_GETCPU_VSYSCALL		"__vdso_getcpu"
     159  
     160  # undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
     161  # define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
     162  
     163  # define INTERNAL_SYSCALL(name, nr, args...) \
     164  	internal_syscall##nr (SYS_ify (name), args)
     165  
     166  # define INTERNAL_SYSCALL_NCS(number, nr, args...) \
     167  	internal_syscall##nr (number, args)
     168  
     169  # define internal_syscall0(number, dummy...)			\
     170  ({ 									\
     171  	long int _sys_result;						\
     172  									\
     173  	{								\
     174  	register long int __a7 asm ("a7") = number;			\
     175  	register long int __a0 asm ("a0");				\
     176  	__asm__ volatile ( 						\
     177  	"scall\n\t" 							\
     178  	: "=r" (__a0)							\
     179  	: "r" (__a7)							\
     180  	: __SYSCALL_CLOBBERS); 						\
     181  	_sys_result = __a0;						\
     182  	}								\
     183  	_sys_result;							\
     184  })
     185  
     186  # define internal_syscall1(number, arg0)				\
     187  ({ 									\
     188  	long int _sys_result;						\
     189  	long int _arg0 = (long int) (arg0);				\
     190  									\
     191  	{								\
     192  	register long int __a7 asm ("a7") = number;			\
     193  	register long int __a0 asm ("a0") = _arg0;			\
     194  	__asm__ volatile ( 						\
     195  	"scall\n\t" 							\
     196  	: "+r" (__a0)							\
     197  	: "r" (__a7)							\
     198  	: __SYSCALL_CLOBBERS); 						\
     199  	_sys_result = __a0;						\
     200  	}								\
     201  	_sys_result;							\
     202  })
     203  
     204  # define internal_syscall2(number, arg0, arg1)	    		\
     205  ({ 									\
     206  	long int _sys_result;						\
     207  	long int _arg0 = (long int) (arg0);				\
     208  	long int _arg1 = (long int) (arg1);				\
     209  									\
     210  	{								\
     211  	register long int __a7 asm ("a7") = number;			\
     212  	register long int __a0 asm ("a0") = _arg0;			\
     213  	register long int __a1 asm ("a1") = _arg1;			\
     214  	__asm__ volatile ( 						\
     215  	"scall\n\t" 							\
     216  	: "+r" (__a0)							\
     217  	: "r" (__a7), "r" (__a1)					\
     218  	: __SYSCALL_CLOBBERS); 						\
     219  	_sys_result = __a0;						\
     220  	}								\
     221  	_sys_result;							\
     222  })
     223  
     224  # define internal_syscall3(number, arg0, arg1, arg2)      		\
     225  ({ 									\
     226  	long int _sys_result;						\
     227  	long int _arg0 = (long int) (arg0);				\
     228  	long int _arg1 = (long int) (arg1);				\
     229  	long int _arg2 = (long int) (arg2);				\
     230  									\
     231  	{								\
     232  	register long int __a7 asm ("a7") = number;			\
     233  	register long int __a0 asm ("a0") = _arg0;			\
     234  	register long int __a1 asm ("a1") = _arg1;			\
     235  	register long int __a2 asm ("a2") = _arg2;			\
     236  	__asm__ volatile ( 						\
     237  	"scall\n\t" 							\
     238  	: "+r" (__a0)							\
     239  	: "r" (__a7), "r" (__a1), "r" (__a2)				\
     240  	: __SYSCALL_CLOBBERS); 						\
     241  	_sys_result = __a0;						\
     242  	}								\
     243  	_sys_result;							\
     244  })
     245  
     246  # define internal_syscall4(number, arg0, arg1, arg2, arg3)	  \
     247  ({ 									\
     248  	long int _sys_result;						\
     249  	long int _arg0 = (long int) (arg0);				\
     250  	long int _arg1 = (long int) (arg1);				\
     251  	long int _arg2 = (long int) (arg2);				\
     252  	long int _arg3 = (long int) (arg3);				\
     253  									\
     254  	{								\
     255  	register long int __a7 asm ("a7") = number;			\
     256  	register long int __a0 asm ("a0") = _arg0;			\
     257  	register long int __a1 asm ("a1") = _arg1;			\
     258  	register long int __a2 asm ("a2") = _arg2;			\
     259  	register long int __a3 asm ("a3") = _arg3;			\
     260  	__asm__ volatile ( 						\
     261  	"scall\n\t" 							\
     262  	: "+r" (__a0)							\
     263  	: "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3)		\
     264  	: __SYSCALL_CLOBBERS); 						\
     265  	_sys_result = __a0;						\
     266  	}								\
     267  	_sys_result;							\
     268  })
     269  
     270  # define internal_syscall5(number, arg0, arg1, arg2, arg3, arg4)   \
     271  ({ 									\
     272  	long int _sys_result;						\
     273  	long int _arg0 = (long int) (arg0);				\
     274  	long int _arg1 = (long int) (arg1);				\
     275  	long int _arg2 = (long int) (arg2);				\
     276  	long int _arg3 = (long int) (arg3);				\
     277  	long int _arg4 = (long int) (arg4);				\
     278  									\
     279  	{								\
     280  	register long int __a7 asm ("a7") = number;			\
     281  	register long int __a0 asm ("a0") = _arg0;			\
     282  	register long int __a1 asm ("a1") = _arg1;			\
     283  	register long int __a2 asm ("a2") = _arg2;			\
     284  	register long int __a3 asm ("a3") = _arg3;			\
     285  	register long int __a4 asm ("a4") = _arg4;			\
     286  	__asm__ volatile ( 						\
     287  	"scall\n\t" 							\
     288  	: "+r" (__a0)							\
     289  	: "r" (__a7), "r"(__a1), "r"(__a2), "r"(__a3), "r" (__a4)	\
     290  	: __SYSCALL_CLOBBERS); 						\
     291  	_sys_result = __a0;						\
     292  	}								\
     293  	_sys_result;							\
     294  })
     295  
     296  # define internal_syscall6(number, arg0, arg1, arg2, arg3, arg4, arg5) \
     297  ({ 									\
     298  	long int _sys_result;						\
     299  	long int _arg0 = (long int) (arg0);				\
     300  	long int _arg1 = (long int) (arg1);				\
     301  	long int _arg2 = (long int) (arg2);				\
     302  	long int _arg3 = (long int) (arg3);				\
     303  	long int _arg4 = (long int) (arg4);				\
     304  	long int _arg5 = (long int) (arg5);				\
     305  									\
     306  	{								\
     307  	register long int __a7 asm ("a7") = number;			\
     308  	register long int __a0 asm ("a0") = _arg0;			\
     309  	register long int __a1 asm ("a1") = _arg1;			\
     310  	register long int __a2 asm ("a2") = _arg2;			\
     311  	register long int __a3 asm ("a3") = _arg3;			\
     312  	register long int __a4 asm ("a4") = _arg4;			\
     313  	register long int __a5 asm ("a5") = _arg5;			\
     314  	__asm__ volatile ( 						\
     315  	"scall\n\t" 							\
     316  	: "+r" (__a0)							\
     317  	: "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3),		\
     318  	  "r" (__a4), "r" (__a5)					\
     319  	: __SYSCALL_CLOBBERS); 						\
     320  	_sys_result = __a0;						\
     321  	}								\
     322  	_sys_result;							\
     323  })
     324  
     325  # define internal_syscall7(number, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \
     326  ({ 									\
     327  	long int _sys_result;						\
     328  	long int _arg0 = (long int) (arg0);				\
     329  	long int _arg1 = (long int) (arg1);				\
     330  	long int _arg2 = (long int) (arg2);				\
     331  	long int _arg3 = (long int) (arg3);				\
     332  	long int _arg4 = (long int) (arg4);				\
     333  	long int _arg5 = (long int) (arg5);				\
     334  	long int _arg6 = (long int) (arg6);				\
     335  									\
     336  	{								\
     337  	register long int __a7 asm ("a7") = number;			\
     338  	register long int __a0 asm ("a0") = _arg0;			\
     339  	register long int __a1 asm ("a1") = _arg1;			\
     340  	register long int __a2 asm ("a2") = _arg2;			\
     341  	register long int __a3 asm ("a3") = _arg3;			\
     342  	register long int __a4 asm ("a4") = _arg4;			\
     343  	register long int __a5 asm ("a5") = _arg5;			\
     344  	register long int __a6 asm ("a6") = _arg6;			\
     345  	__asm__ volatile ( 						\
     346  	"scall\n\t" 							\
     347  	: "+r" (__a0)							\
     348  	: "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3),		\
     349  	  "r" (__a4), "r" (__a5), "r" (__a6)				\
     350  	: __SYSCALL_CLOBBERS); 						\
     351  	_sys_result = __a0;						\
     352  	}								\
     353  	_sys_result;							\
     354  })
     355  
     356  # define __SYSCALL_CLOBBERS "memory"
     357  
     358  extern long int __syscall_error (long int neg_errno);
     359  
     360  #endif /* ! __ASSEMBLER__ */
     361  
     362  #endif /* linux/riscv/sysdep.h */