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