1 /* Copyright (C) 1992-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #ifndef _LINUX_SH_SYSDEP_H
19 #define _LINUX_SH_SYSDEP_H 1
20 
21 /* There is some commonality.  */
22 #include <sysdeps/unix/sysv/linux/sysdep.h>
23 #include <sysdeps/unix/sh/sysdep.h>
24 #include <tls.h>
25 
26 /* For Linux we can use the system call table in the header file
27 	/usr/include/asm/unistd.h
28    of the kernel.  But these symbols do not follow the SYS_* syntax
29    so we have to redefine the `SYS_ify' macro here.  */
30 #undef SYS_ify
31 #define SYS_ify(syscall_name)	(__NR_##syscall_name)
32 
33 
34 #ifdef __ASSEMBLER__
35 
36 /* Linux uses a negative return value to indicate syscall errors,
37    unlike most Unices, which use the condition codes' carry flag.
38 
39    Since version 2.1 the return value of a system call might be
40    negative even if the call succeeded.  E.g., the `lseek' system call
41    might return a large offset.  Therefore we must not anymore test
42    for < 0, but test for a real error by making sure the value in R0
43    is a real error number.  Linus said he will make sure the no syscall
44    returns a value in -1 .. -4095 as a valid result so we can savely
45    test with -4095.  */
46 
47 #define _IMM1 #-1
48 #define _IMM12 #-12
49 #undef	PSEUDO
50 #define	PSEUDO(name, syscall_name, args) \
51  .text; \
52  ENTRY (name); \
53     DO_CALL (syscall_name, args); \
54     mov r0,r1; \
55     mov _IMM12,r2; \
56     shad r2,r1; \
57     not r1,r1; \
58     tst r1,r1; \
59     bf .Lpseudo_end; \
60     SYSCALL_ERROR_HANDLER; \
61  .Lpseudo_end:
62 
63 #undef	PSEUDO_END
64 #define	PSEUDO_END(name) \
65   END (name)
66 
67 #undef	PSEUDO_NOERRNO
68 #define	PSEUDO_NOERRNO(name, syscall_name, args) \
69  .text; \
70  ENTRY (name); \
71     DO_CALL (syscall_name, args)
72 
73 #undef	PSEUDO_END_NOERRNO
74 #define	PSEUDO_END_NOERRNO(name) \
75   END (name)
76 
77 #define ret_NOERRNO ret
78 
79 #define	PSEUDO_ERRVAL(name, syscall_name, args) \
80  .text; \
81  ENTRY (name); \
82     DO_CALL (syscall_name, args);
83 
84 #undef	PSEUDO_END_ERRVAL
85 #define	PSEUDO_END_ERRVAL(name) \
86   END (name)
87 
88 #define ret_ERRVAL ret
89 
90 #ifndef PIC
91 # define SYSCALL_ERROR_HANDLER	\
92 	mov.l 0f,r1; \
93 	jmp @r1; \
94 	 mov r0,r4; \
95 	.align 2; \
96      0: .long __syscall_error
97 #else
98 # if RTLD_PRIVATE_ERRNO
99 #  define SYSCALL_ERROR_HANDLER	\
100 	neg r0,r1; \
101 	mov r12,r2; \
102 	cfi_register (r12, r2); \
103 	mov.l 0f,r12; \
104 	mova 0f,r0; \
105 	add r0,r12; \
106 	mov.l 1f,r0; \
107 	mov.l r1,@(r0,r12); \
108 	mov r2,r12; \
109 	cfi_restore (r12); \
110 	bra .Lpseudo_end; \
111 	 mov _IMM1,r0; \
112 	.align 2; \
113      0: .long _GLOBAL_OFFSET_TABLE_; \
114      1: .long rtld_errno@GOTOFF
115 
116 # elif defined _LIBC_REENTRANT
117 
118 #  if IS_IN (libc)
119 #   define SYSCALL_ERROR_ERRNO __libc_errno
120 #  else
121 #   define SYSCALL_ERROR_ERRNO errno
122 #  endif
123 #  define SYSCALL_ERROR_HANDLER \
124 	neg r0,r1; \
125 	mov r12,r2; \
126 	cfi_register (r12, r2); \
127 	mov.l 0f,r12; \
128 	mova 0f,r0; \
129 	add r0,r12; \
130 	mov.l 1f,r0; \
131 	stc gbr, r4; \
132 	mov.l @(r0,r12),r0; \
133 	mov r2,r12; \
134 	cfi_restore (r12); \
135 	add r4,r0; \
136 	mov.l r1,@r0; \
137 	bra .Lpseudo_end; \
138 	 mov _IMM1,r0; \
139 	.align 2; \
140      0: .long _GLOBAL_OFFSET_TABLE_; \
141      1: .long SYSCALL_ERROR_ERRNO@GOTTPOFF
142 # else
143 /* Store (-r0) into errno through the GOT.  */
144 #  define SYSCALL_ERROR_HANDLER						      \
145 	neg r0,r1; \
146 	mov r12,r2; \
147 	cfi_register (r12, r2); \
148 	mov.l 0f,r12; \
149 	mova 0f,r0; \
150 	add r0,r12; \
151 	mov.l 1f,r0; \
152 	mov.l @(r0,r12),r0; \
153 	mov r2,r12; \
154 	cfi_restore (r12); \
155 	mov.l r1,@r0; \
156 	bra .Lpseudo_end; \
157 	 mov _IMM1,r0; \
158 	.align 2; \
159      0: .long _GLOBAL_OFFSET_TABLE_; \
160      1: .long errno@GOT
161 # endif	/* _LIBC_REENTRANT */
162 #endif	/* PIC */
163 
164 # ifdef NEED_SYSCALL_INST_PAD
165 #  define SYSCALL_INST_PAD \
166 	or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0
167 # else
168 #  define SYSCALL_INST_PAD
169 # endif
170 
171 #define SYSCALL_INST0	trapa #0x10
172 #define SYSCALL_INST1	trapa #0x11
173 #define SYSCALL_INST2	trapa #0x12
174 #define SYSCALL_INST3	trapa #0x13
175 #define SYSCALL_INST4	trapa #0x14
176 #define SYSCALL_INST5	mov.l @(0,r15),r0; trapa #0x15
177 #define SYSCALL_INST6	mov.l @(0,r15),r0; mov.l @(4,r15),r1; trapa #0x16
178 
179 #undef	DO_CALL
180 #define DO_CALL(syscall_name, args)	\
181     mov.l 1f,r3;			\
182     SYSCALL_INST##args;			\
183     SYSCALL_INST_PAD;			\
184     bra 2f;				\
185      nop;				\
186     .align 2;				\
187  1: .long SYS_ify (syscall_name);	\
188  2:
189 
190 #else /* not __ASSEMBLER__ */
191 
192 #define SYSCALL_INST_STR0	"trapa #0x10\n\t"
193 #define SYSCALL_INST_STR1	"trapa #0x11\n\t"
194 #define SYSCALL_INST_STR2	"trapa #0x12\n\t"
195 #define SYSCALL_INST_STR3	"trapa #0x13\n\t"
196 #define SYSCALL_INST_STR4	"trapa #0x14\n\t"
197 #define SYSCALL_INST_STR5	"trapa #0x15\n\t"
198 #define SYSCALL_INST_STR6	"trapa #0x16\n\t"
199 
200 # ifdef NEED_SYSCALL_INST_PAD
201 #  define SYSCALL_INST_PAD "\
202 	or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0"
203 # else
204 #  define SYSCALL_INST_PAD
205 # endif
206 
207 #define ASMFMT_0
208 #define ASMFMT_1 \
209 	, "r" (r4)
210 #define ASMFMT_2 \
211 	, "r" (r4), "r" (r5)
212 #define ASMFMT_3 \
213 	, "r" (r4), "r" (r5), "r" (r6)
214 #define ASMFMT_4 \
215 	, "r" (r4), "r" (r5), "r" (r6), "r" (r7)
216 #define ASMFMT_5 \
217 	, "r" (r4), "r" (r5), "r" (r6), "r" (r7), "0" (r0)
218 #define ASMFMT_6 \
219 	, "r" (r4), "r" (r5), "r" (r6), "r" (r7), "0" (r0), "r" (r1)
220 #define ASMFMT_7 \
221 	, "r" (r4), "r" (r5), "r" (r6), "r" (r7), "0" (r0), "r" (r1), "r" (r2)
222 
223 #define SUBSTITUTE_ARGS_0()
224 #define SUBSTITUTE_ARGS_1(arg1) \
225 	long int _arg1 = (long int) (arg1);				      \
226 	register long int r4 asm ("%r4") = (long int) (_arg1)
227 #define SUBSTITUTE_ARGS_2(arg1, arg2) \
228 	long int _arg1 = (long int) (arg1);				      \
229 	long int _arg2 = (long int) (arg2);				      \
230 	register long int r4 asm ("%r4") = (long int) (_arg1);		      \
231 	register long int r5 asm ("%r5") = (long int) (_arg2)
232 #define SUBSTITUTE_ARGS_3(arg1, arg2, arg3) \
233 	long int _arg1 = (long int) (arg1);				      \
234 	long int _arg2 = (long int) (arg2);				      \
235 	long int _arg3 = (long int) (arg3);				      \
236 	register long int r4 asm ("%r4") = (long int) (_arg1);		      \
237 	register long int r5 asm ("%r5") = (long int) (_arg2);		      \
238 	register long int r6 asm ("%r6") = (long int) (_arg3)
239 #define SUBSTITUTE_ARGS_4(arg1, arg2, arg3, arg4) \
240 	long int _arg1 = (long int) (arg1);				      \
241 	long int _arg2 = (long int) (arg2);				      \
242 	long int _arg3 = (long int) (arg3);				      \
243 	long int _arg4 = (long int) (arg4);				      \
244 	register long int r4 asm ("%r4") = (long int) (_arg1);		      \
245 	register long int r5 asm ("%r5") = (long int) (_arg2);		      \
246 	register long int r6 asm ("%r6") = (long int) (_arg3);		      \
247 	register long int r7 asm ("%r7") = (long int) (_arg4)
248 #define SUBSTITUTE_ARGS_5(arg1, arg2, arg3, arg4, arg5) \
249 	long int _arg1 = (long int) (arg1);				      \
250 	long int _arg2 = (long int) (arg2);				      \
251 	long int _arg3 = (long int) (arg3);				      \
252 	long int _arg4 = (long int) (arg4);				      \
253 	long int _arg5 = (long int) (arg5);				      \
254 	register long int r4 asm ("%r4") = (long int) (_arg1);		      \
255 	register long int r5 asm ("%r5") = (long int) (_arg2);		      \
256 	register long int r6 asm ("%r6") = (long int) (_arg3);		      \
257 	register long int r7 asm ("%r7") = (long int) (_arg4);		      \
258 	register long int r0 asm ("%r0") = (long int) (_arg5)
259 #define SUBSTITUTE_ARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \
260 	long int _arg1 = (long int) (arg1);				      \
261 	long int _arg2 = (long int) (arg2);				      \
262 	long int _arg3 = (long int) (arg3);				      \
263 	long int _arg4 = (long int) (arg4);				      \
264 	long int _arg5 = (long int) (arg5);				      \
265 	long int _arg6 = (long int) (arg6);				      \
266 	register long int r4 asm ("%r4") = (long int)(_arg1);		      \
267 	register long int r5 asm ("%r5") = (long int) (_arg2);		      \
268 	register long int r6 asm ("%r6") = (long int) (_arg3);		      \
269 	register long int r7 asm ("%r7") = (long int) (_arg4);		      \
270 	register long int r0 asm ("%r0") = (long int) (_arg5);		      \
271 	register long int r1 asm ("%r1") = (long int) (_arg6)
272 #define SUBSTITUTE_ARGS_7(arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
273 	long int _arg1 = (long int) (arg1);				      \
274 	long int _arg2 = (long int) (arg2);				      \
275 	long int _arg3 = (long int) (arg3);				      \
276 	long int _arg4 = (long int) (arg4);				      \
277 	long int _arg5 = (long int) (arg5);				      \
278 	long int _arg6 = (long int) (arg6);				      \
279 	long int _arg7 = (long int) (arg7);				      \
280 	register long int r4 asm ("%r4") = (long int) (_arg1);		      \
281 	register long int r5 asm ("%r5") = (long int) (_arg2);		      \
282 	register long int r6 asm ("%r6") = (long int) (_arg3);		      \
283 	register long int r7 asm ("%r7") = (long int) (_arg4);		      \
284 	register long int r0 asm ("%r0") = (long int) (_arg5);		      \
285 	register long int r1 asm ("%r1") = (long int) (_arg6);		      \
286 	register long int r2 asm ("%r2") = (long int) (_arg7)
287 
288 #undef INTERNAL_SYSCALL
289 #define INTERNAL_SYSCALL(name, nr, args...) \
290   ({									      \
291     unsigned long int resultvar;					      \
292     register long int r3 asm ("%r3") = SYS_ify (name);			      \
293     SUBSTITUTE_ARGS_##nr(args);						      \
294 									      \
295     asm volatile (SYSCALL_INST_STR##nr SYSCALL_INST_PAD			      \
296 		  : "=z" (resultvar)					      \
297 		  : "r" (r3) ASMFMT_##nr				      \
298 		  : "memory", "t");					      \
299 									      \
300     (int) resultvar; })
301 
302 /* The _NCS variant allows non-constant syscall numbers.  */
303 #define INTERNAL_SYSCALL_NCS(name, nr, args...) \
304   ({									      \
305     unsigned long int resultvar;					      \
306     register long int r3 asm ("%r3") = (name);				      \
307     SUBSTITUTE_ARGS_##nr(args);						      \
308 									      \
309     asm volatile (SYSCALL_INST_STR##nr SYSCALL_INST_PAD			      \
310 		  : "=z" (resultvar)					      \
311 		  : "r" (r3) ASMFMT_##nr				      \
312 		  : "memory", "t");					      \
313 									      \
314     (int) resultvar; })
315 
316 #endif	/* __ASSEMBLER__ */
317 
318 /* Pointer mangling support.  */
319 #if IS_IN (rtld)
320 /* We cannot use the thread descriptor because in ld.so we use setjmp
321    earlier than the descriptor is initialized.  Using a global variable
322    is too complicated here since we have no PC-relative addressing mode.  */
323 #else
324 # ifdef __ASSEMBLER__
325 #  define PTR_MANGLE(reg, tmp) \
326      stc gbr,tmp; mov.l @(POINTER_GUARD,tmp),tmp; xor tmp,reg
327 #  define PTR_MANGLE2(reg, tmp)	xor tmp,reg
328 #  define PTR_DEMANGLE(reg, tmp)	PTR_MANGLE (reg, tmp)
329 #  define PTR_DEMANGLE2(reg, tmp)	PTR_MANGLE2 (reg, tmp)
330 # else
331 #  define PTR_MANGLE(var) \
332      (var) = (void *) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
333 #  define PTR_DEMANGLE(var)	PTR_MANGLE (var)
334 # endif
335 #endif
336 
337 #endif /* linux/sh/sysdep.h */
338