master
  1/* Assembler macros for ARC.
  2   Copyright (C) 2020-2025 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				\
119L (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)
138extern long int __syscall_error (long int);
139hidden_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 */