1  /* Assembler macros for ARC.
       2     Copyright (C) 2020-2023 Free Software Foundation, Inc.
       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_ARC_SYSDEP_H
      20  #define _LINUX_ARC_SYSDEP_H 1
      21  
      22  #include <sysdeps/arc/sysdep.h>
      23  #include <bits/wordsize.h>
      24  #include <sysdeps/unix/sysdep.h>
      25  #include <sysdeps/unix/sysv/linux/sysdep.h>
      26  
      27  /* "workarounds" for generic code needing to handle 64-bit time_t.  */
      28  
      29  /* Fix sysdeps/unix/sysv/linux/clock_getcpuclockid.c.  */
      30  #define __NR_clock_getres	__NR_clock_getres_time64
      31  /* Fix sysdeps/nptl/lowlevellock-futex.h.  */
      32  #define __NR_futex		__NR_futex_time64
      33  /* Fix sysdeps/unix/sysv/linux/pause.c.  */
      34  #define __NR_ppoll		__NR_ppoll_time64
      35  /* Fix sysdeps/unix/sysv/linux/select.c.  */
      36  #define __NR_pselect6		__NR_pselect6_time64
      37  /* Fix sysdeps/unix/sysv/linux/recvmmsg.c.  */
      38  #define __NR_recvmmsg		__NR_recvmmsg_time64
      39  /* Fix sysdeps/unix/sysv/linux/sigtimedwait.c.  */
      40  #define __NR_rt_sigtimedwait	__NR_rt_sigtimedwait_time64
      41  /* Fix sysdeps/unix/sysv/linux/semtimedop.c.  */
      42  #define __NR_semtimedop		__NR_semtimedop_time64
      43  /* Hack sysdeps/unix/sysv/linux/generic/utimes.c.  */
      44  #define __NR_utimensat		__NR_utimensat_time64
      45  
      46  /* For RTLD_PRIVATE_ERRNO.  */
      47  #include <dl-sysdep.h>
      48  
      49  #include <tls.h>
      50  
      51  #undef SYS_ify
      52  #define SYS_ify(syscall_name)   __NR_##syscall_name
      53  
      54  #ifdef __ASSEMBLER__
      55  
      56  /* This is a "normal" system call stub: if there is an error,
      57     it returns -1 and sets errno.  */
      58  
      59  # undef PSEUDO
      60  # define PSEUDO(name, syscall_name, args)			\
      61    PSEUDO_NOERRNO(name, syscall_name, args)	ASM_LINE_SEP	\
      62      brhi   r0, -4096, L (call_syscall_err)	ASM_LINE_SEP
      63  
      64  # define ret	j_s  [blink]
      65  
      66  # undef PSEUDO_END
      67  # define PSEUDO_END(name)					\
      68    SYSCALL_ERROR_HANDLER				ASM_LINE_SEP	\
      69    END (name)
      70  
      71  /* --------- Helper for SYSCALL_NOERRNO -----------
      72     This kind of system call stub never returns an error.
      73     We return the return value register to the caller unexamined.  */
      74  
      75  # undef PSEUDO_NOERRNO
      76  # define PSEUDO_NOERRNO(name, syscall_name, args)		\
      77    .text						ASM_LINE_SEP	\
      78    ENTRY (name)					ASM_LINE_SEP	\
      79      DO_CALL (syscall_name, args)		ASM_LINE_SEP	\
      80  
      81  /* Return the return value register unexamined. Since r0 is both
      82     syscall return reg and function return reg, no work needed.  */
      83  # define ret_NOERRNO						\
      84    j_s  [blink]		ASM_LINE_SEP
      85  
      86  # undef PSEUDO_END_NOERRNO
      87  # define PSEUDO_END_NOERRNO(name)				\
      88    END (name)
      89  
      90  /* --------- Helper for SYSCALL_ERRVAL -----------
      91     This kind of system call stub returns the errno code as its return
      92     value, or zero for success.  We may massage the kernel's return value
      93     to meet that ABI, but we never set errno here.  */
      94  
      95  # undef PSEUDO_ERRVAL
      96  # define PSEUDO_ERRVAL(name, syscall_name, args)		\
      97    PSEUDO_NOERRNO(name, syscall_name, args)	ASM_LINE_SEP
      98  
      99  /* Don't set errno, return kernel error (in errno form) or zero.  */
     100  # define ret_ERRVAL						\
     101    rsub   r0, r0, 0				ASM_LINE_SEP	\
     102    ret_NOERRNO
     103  
     104  # undef PSEUDO_END_ERRVAL
     105  # define PSEUDO_END_ERRVAL(name)				\
     106    END (name)
     107  
     108  
     109  /* To reduce the code footprint, we confine the actual errno access
     110     to single place in __syscall_error().
     111     This takes raw kernel error value, sets errno and returns -1.  */
     112  # if IS_IN (libc)
     113  #  define CALL_ERRNO_SETTER_C	bl     PLTJMP(HIDDEN_JUMPTARGET(__syscall_error))
     114  # else
     115  #  define CALL_ERRNO_SETTER_C	bl     PLTJMP(__syscall_error)
     116  # endif
     117  
     118  # define SYSCALL_ERROR_HANDLER				\
     119  L (call_syscall_err):			ASM_LINE_SEP	\
     120      push_s   blink			ASM_LINE_SEP	\
     121      cfi_adjust_cfa_offset (4)		ASM_LINE_SEP	\
     122      cfi_rel_offset (blink, 0)		ASM_LINE_SEP	\
     123      CALL_ERRNO_SETTER_C			ASM_LINE_SEP	\
     124      pop_s  blink			ASM_LINE_SEP	\
     125      cfi_adjust_cfa_offset (-4)		ASM_LINE_SEP	\
     126      cfi_restore (blink)			ASM_LINE_SEP	\
     127      j_s      [blink]
     128  
     129  # define DO_CALL(syscall_name, args)			\
     130      mov    r8, __NR_##syscall_name	ASM_LINE_SEP	\
     131      ARC_TRAP_INSN			ASM_LINE_SEP
     132  
     133  # define ARC_TRAP_INSN	trap_s 0
     134  
     135  #else  /* !__ASSEMBLER__ */
     136  
     137  # if IS_IN (libc)
     138  extern long int __syscall_error (long int);
     139  hidden_proto (__syscall_error)
     140  # endif
     141  
     142  # define ARC_TRAP_INSN	"trap_s 0	\n\t"
     143  
     144  # define HAVE_CLONE3_WRAPPER	1
     145  
     146  # undef INTERNAL_SYSCALL_NCS
     147  # define INTERNAL_SYSCALL_NCS(number, nr_args, args...)	\
     148    ({								\
     149      /* Per ABI, r0 is 1st arg and return reg.  */		\
     150      register long int __ret __asm__("r0");			\
     151      register long int _sys_num __asm__("r8");			\
     152  								\
     153      LOAD_ARGS_##nr_args (number, args)				\
     154  								\
     155      __asm__ volatile (						\
     156                        ARC_TRAP_INSN				\
     157                        : "+r" (__ret)				\
     158                        : "r"(_sys_num) ASM_ARGS_##nr_args	\
     159                        : "memory");				\
     160                                                                  \
     161      __ret; })
     162  
     163  # undef INTERNAL_SYSCALL
     164  # define INTERNAL_SYSCALL(name, nr, args...) 	\
     165    INTERNAL_SYSCALL_NCS(__NR_##name, nr, args)
     166  
     167  /* Macros for setting up inline __asm__ input regs.  */
     168  # define ASM_ARGS_0
     169  # define ASM_ARGS_1	ASM_ARGS_0, "r" (__ret)
     170  # define ASM_ARGS_2	ASM_ARGS_1, "r" (_arg2)
     171  # define ASM_ARGS_3	ASM_ARGS_2, "r" (_arg3)
     172  # define ASM_ARGS_4	ASM_ARGS_3, "r" (_arg4)
     173  # define ASM_ARGS_5	ASM_ARGS_4, "r" (_arg5)
     174  # define ASM_ARGS_6	ASM_ARGS_5, "r" (_arg6)
     175  # define ASM_ARGS_7	ASM_ARGS_6, "r" (_arg7)
     176  
     177  /* Macros for converting sys-call wrapper args into sys call args.  */
     178  # define LOAD_ARGS_0(nm, arg)				\
     179    _sys_num = (long int) (nm);
     180  
     181  # define LOAD_ARGS_1(nm, arg1)				\
     182    __ret = (long int) (arg1);					\
     183    LOAD_ARGS_0 (nm, arg1)
     184  
     185  /* Note that the use of _tmpX might look superfluous, however it is needed
     186     to ensure that register variables are not clobbered if arg happens to be
     187     a function call itself. e.g. sched_setaffinity() calling getpid() for arg2
     188     Also this specific order of recursive calling is important to segregate
     189     the tmp args evaluation (function call case described above) and assignment
     190     of register variables.  */
     191  
     192  # define LOAD_ARGS_2(nm, arg1, arg2)			\
     193    long int _tmp2 = (long int) (arg2);			\
     194    LOAD_ARGS_1 (nm, arg1)				\
     195    register long int _arg2 __asm__ ("r1") = _tmp2;
     196  
     197  # define LOAD_ARGS_3(nm, arg1, arg2, arg3)		\
     198    long int _tmp3 = (long int) (arg3);			\
     199    LOAD_ARGS_2 (nm, arg1, arg2)				\
     200    register long int _arg3 __asm__ ("r2") = _tmp3;
     201  
     202  #define LOAD_ARGS_4(nm, arg1, arg2, arg3, arg4)		\
     203    long int _tmp4 = (long int) (arg4);			\
     204    LOAD_ARGS_3 (nm, arg1, arg2, arg3)			\
     205    register long int _arg4 __asm__ ("r3") = _tmp4;
     206  
     207  # define LOAD_ARGS_5(nm, arg1, arg2, arg3, arg4, arg5)	\
     208    long int _tmp5 = (long int) (arg5);			\
     209    LOAD_ARGS_4 (nm, arg1, arg2, arg3, arg4)		\
     210    register long int _arg5 __asm__ ("r4") = _tmp5;
     211  
     212  # define LOAD_ARGS_6(nm,  arg1, arg2, arg3, arg4, arg5, arg6)\
     213    long int _tmp6 = (long int) (arg6);			\
     214    LOAD_ARGS_5 (nm, arg1, arg2, arg3, arg4, arg5)	\
     215    register long int _arg6 __asm__ ("r5") = _tmp6;
     216  
     217  # define LOAD_ARGS_7(nm, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\
     218    long int _tmp7 = (int) (arg7);				\
     219    LOAD_ARGS_6 (nm, arg1, arg2, arg3, arg4, arg5, arg6)	\
     220    register long int _arg7 __asm__ ("r6") = _tmp7;
     221  
     222  # undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
     223  # define HAVE_INTERNAL_BRK_ADDR_SYMBOL  1
     224  
     225  #endif /* !__ASSEMBLER__ */
     226  
     227  #endif /* linux/arc/sysdep.h */