1 /* Assembly macros for C-SKY.
2    Copyright (C) 2018-2022 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_CSKY_SYSDEP_H
20 #define _LINUX_CSKY_SYSDEP_H 1
21 
22 /* There is some commonality.  */
23 #include <sysdeps/unix/sysv/linux/generic/sysdep.h>
24 #include <sysdeps/unix/sysv/linux/sysdep.h>
25 #include <sysdeps/csky/sysdep.h>
26 
27 /* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO.  */
28 #include <dl-sysdep.h>
29 
30 #include <tls.h>
31 
32 /* In order to get __set_errno() definition in INLINE_SYSCALL.  */
33 #ifndef __ASSEMBLER__
34 # include <errno.h>
35 #endif
36 
37 #undef SYS_ify
38 #define SYS_ify(syscall_name)  (__NR_##syscall_name)
39 
40 #ifdef __ASSEMBLER__
41 /* Linux uses a negative return value to indicate syscall errors,
42    unlike most Unices, which use the condition codes' carry flag.
43 
44    Since version 2.1 the return value of a system call might be
45    negative even if the call succeeded.  E.g., the `lseek' system call
46    might return a large offset.  Therefore we must not anymore test
47    for < 0, but test for a real error by making sure the value in R0
48    is a real error number.  Linus said he will make sure the no syscall
49    returns a value in -1 .. -4095 as a valid result so we can safely
50    test with -4095.  */
51 
52 # undef PSEUDO
53 # define PSEUDO(name, syscall_name, args)	\
54   .text;					\
55   ENTRY (name);					\
56   DO_CALL (syscall_name, args);
57 
58 # define GETGB				\
59 	grs	t0, .Lgetpc;		\
60 .Lgetpc:				\
61 	lrw	gb, .Lgetpc@GOTPC;	\
62 	addu	gb, t0;
63 
64 # if IS_IN (libc)
65 #  ifdef __PIC__
66 #   define PSEUDO_RET			\
67 	btsti	a0, 31;			\
68 	bf	1f;			\
69 	subi	sp, 8;			\
70 	st.w	lr, (sp);		\
71 	st.w	gb, (sp, 4);		\
72 	GETGB;				\
73 	lrw	a2, SYSCALL_ERROR@PLT;	\
74 	add	a2, gb;			\
75 	ld.w	a2, (a2);		\
76 	jsr	a2;			\
77 	ld.w	lr, (sp);		\
78 	ld.w	gb, (sp, 4);		\
79 	addi	sp, 8;			\
80 1:					\
81 	rts
82 #  else
83 #   define PSEUDO_RET			\
84 	btsti	a0, 31;			\
85 	bf	1f;			\
86 	jmpi	SYSCALL_ERROR;		\
87 1:					\
88 	rts
89 #  endif
90 # else
91 #  ifdef __PIC__
92 #   define PSEUDO_RET			\
93 	btsti	a0, 31;			\
94 	bf	1f;			\
95 	subi	sp, 8;			\
96 	st.w	lr, (sp);		\
97 	st.w	gb, (sp, 4);		\
98 	GETGB;				\
99 	bsr	SYSCALL_ERROR;		\
100 	ld.w	lr, (sp);		\
101 	ld.w	gb, (sp, 4);		\
102 	addi	sp, 8;			\
103 1:					\
104 	rts
105 #  else
106 #   define PSEUDO_RET			\
107 	btsti	a0, 31;			\
108 	bt	SYSCALL_ERROR;		\
109 	rts
110 #  endif
111 # endif
112 
113 # undef ret
114 # define ret PSEUDO_RET
115 
116 # undef PSEUDO_END
117 # define PSEUDO_END(name)		\
118   .align 4;				\
119   SYSCALL_ERROR_HANDLER;		\
120   END (name)
121 
122 # undef PSEUDO_NOERRNO
123 # define PSEUDO_NOERRNO(name, syscall_name, args)	\
124   .text;						\
125   ENTRY (name);						\
126   DO_CALL (syscall_name, args)
127 
128 # define PSEUDO_RET_NOERRNO rts
129 
130 # undef ret_NOERRNO
131 # define ret_NOERRNO PSEUDO_RET_NOERRNO
132 
133 # undef PSEUDO_END_NOERRNO
134 # define PSEUDO_END_NOERRNO(name) END (name)
135 
136 /* The function has to return the error code.  */
137 # undef PSEUDO_ERRVAL
138 # define PSEUDO_ERRVAL(name, syscall_name, args)	\
139   .text;						\
140   ENTRY (name)						\
141   DO_CALL (syscall_name, args);				\
142   not	a0;						\
143   addi	a0, 1
144 
145 # undef PSEUDO_END_ERRVAL
146 # define PSEUDO_END_ERRVAL(name) END (name)
147 
148 # define ret_ERRVAL rts
149 
150 # if !IS_IN (libc)
151 #  define SYSCALL_ERROR __local_syscall_error
152 #  if RTLD_PRIVATE_ERRNO
153 #   ifdef __PIC__
154 #    define SYSCALL_ERROR_HANDLER	\
155 __local_syscall_error:			\
156 	lrw	a1, rtld_errno@PLT; 	\
157 	addu	a1, gb;			\
158 	ldw	a1, (a1);		\
159 	rsubi	a0, 0;			\
160 	stw	a0, (a1);		\
161 	bmaski	a0, 0;			\
162 	rts
163 #   else /* __PIC__ */
164 #    define SYSCALL_ERROR_HANDLER	\
165 __local_syscall_error:			\
166 	lrw	a1, rtld_errno;		\
167 	rsubi	a0, 0;			\
168 	stw	a0, (a1);		\
169 	bmaski	a0, 0;			\
170 	rts
171 #   endif /* __PIC__ */
172 #  else /* !RTLD_PRIVATE_ERRNO */
173 #   ifdef __PIC__
174 #    define SYSCALL_ERROR_HANDLER		\
175 __local_syscall_error:				\
176 	subi	sp, 8;				\
177 	stw	a0, (sp, 0);			\
178 	stw	r15, (sp, 4);			\
179 	lrw	a1, __errno_location@PLT;	\
180 	add	a1, gb;				\
181 	ldw	a1, (a1);			\
182 	jsr	a1;				\
183 	ldw	a1, (sp, 0); /* load errno*/	\
184 	ldw	r15, (sp, 4);			\
185 	addi	sp, 8;				\
186 	movi	a2, 0;				\
187 	rsub	a1, a1, a2;			\
188 	stw	a1, (a0);			\
189 	bmaski	a0, 0;				\
190 	rts
191 #    else
192 #     define SYSCALL_ERROR_HANDLER 		\
193 __local_syscall_error:				\
194 	subi	sp, 8;				\
195 	stw	a0, (sp, 0);			\
196 	stw	r15, (sp, 4);			\
197 	lrw	a1, __errno_location;		\
198 	jsr	a1;				\
199 	ldw	a1, (sp, 0); /* load errno */	\
200 	ldw	r15, (sp, 4);			\
201 	addi	sp, 8;				\
202 	movi	a2, 0;				\
203 	rsub	a1, a1, a2;			\
204 	stw	a1, (a0);			\
205 	bmaski	a0, 0;				\
206 	rts
207 #   endif /* __PIC__ */
208 #  endif/* RTLD_PRIVATE_ERROR */
209 # else
210 #  define SYSCALL_ERROR_HANDLER  /* Nothing here; code in sysdep.S is used.  */
211 #  define SYSCALL_ERROR __syscall_error
212 # endif/* IS_IN (libc) */
213 
214 /* define DO_CALL */
215 # undef DO_CALL
216 # define DO_CALL(syscall_name, args)	\
217   DOARGS_##args;			\
218   lrw	r7, SYS_ify(syscall_name);	\
219   trap	0;				\
220   UNDOARGS_##args
221 
222 # undef  DOARGS_0
223 # define DOARGS_0			\
224 	subi	sp, 8;			\
225 	cfi_adjust_cfa_offset (8);	\
226 	stw	r7, (sp, 0);		\
227 	cfi_rel_offset (r7, 0);
228 
229 # undef  DOARGS_1
230 # define DOARGS_1 DOARGS_0
231 # undef  DOARGS_2
232 # define DOARGS_2 DOARGS_0
233 # undef  DOARGS_3
234 # define DOARGS_3 DOARGS_0
235 # undef  DOARGS_4
236 # define DOARGS_4 DOARGS_0
237 # undef  DOARGS_5
238 # define DOARGS_5			\
239 	subi	sp, 8;			\
240 	cfi_adjust_cfa_offset (8);	\
241 	stw	r7, (sp, 0);		\
242 	cfi_rel_offset (7, 0);		\
243 	stw	r4, (sp, 4);		\
244 	cfi_rel_offset (4, 4);		\
245 	ldw	r4, (sp, 8)
246 # undef  DOARGS_6
247 # define DOARGS_6			\
248 	subi	sp, 16;			\
249 	cfi_adjust_cfa_offset (16);	\
250 	stw	r7, (sp, 0);		\
251 	cfi_rel_offset (7, 0);		\
252 	stw	r4, (sp, 4);		\
253 	cfi_rel_offset (4, 4);		\
254 	stw	r5, (sp, 8);		\
255 	cfi_rel_offset (5, 8);		\
256 	ldw	r4, (sp, 16);		\
257 	ldw	r5, (sp, 20)
258 
259 # undef  UNDOARGS_0
260 # define UNDOARGS_0 \
261   ldw  r7, (sp, 0); \
262   cfi_restore (r7); \
263   addi sp, 8;   \
264   cfi_adjust_cfa_offset (-8);
265 
266 # undef  UNDOARGS_1
267 # define UNDOARGS_1 UNDOARGS_0
268 # undef  UNDOARGS_2
269 # define UNDOARGS_2 UNDOARGS_0
270 # undef  UNDOARGS_3
271 # define UNDOARGS_3 UNDOARGS_0
272 # undef  UNDOARGS_4
273 # define UNDOARGS_4 UNDOARGS_0
274 # undef  UNDOARGS_5
275 # define UNDOARGS_5			\
276 	ldw	r7, (sp, 0);		\
277 	cfi_restore (r4);		\
278 	ldw	r4, (sp, 4);		\
279 	cfi_restore (r4);		\
280 	addi	sp, 8;			\
281 	cfi_adjust_cfa_offset (-8);
282 
283 # undef  UNDOARGS_6
284 # define UNDOARGS_6			\
285 	ldw	r7, (sp, 0);		\
286 	cfi_restore (r7);		\
287 	ldw	r4, (sp, 4);		\
288 	cfi_restore (r4);		\
289 	ldw	r5, (sp, 8);		\
290 	cfi_restore (r5);		\
291 	addi	sp, 16;			\
292 	cfi_adjust_cfa_offset (-16);
293 
294 #else /* not __ASSEMBLER__ */
295 
296 # undef INTERNAL_SYSCALL_RAW
297 #  define INTERNAL_SYSCALL_RAW0(name, dummy...)				\
298   ({unsigned int __sys_result;						\
299      {									\
300        register int _a1 __asm__ ("a0"), _nr __asm__ ("r7");		\
301        _nr = name;							\
302        __asm__ __volatile__ ("trap  0 \n\t"				\
303 			     : "=r" (_a1)				\
304 			     : "r" (_nr)				\
305 			     : "memory");				\
306 	       __sys_result = _a1;					\
307      }									\
308      (int) __sys_result; })
309 
310 #  define INTERNAL_SYSCALL_RAW1(name, arg1)				\
311   ({unsigned int __sys_result;						\
312     register int _tmp_arg1 = (int)(arg1);				\
313      {									\
314        register int _a1 __asm__ ("a0"), _nr __asm__ ("r7");		\
315        _a1 = _tmp_arg1;							\
316        _nr = name;							\
317        __asm__ __volatile__ ("trap  0 \n\t"				\
318 			     : "=r" (_a1)				\
319 			     : "r" (_nr), "r" (_a1)			\
320 			     : "memory");				\
321 	       __sys_result = _a1;					\
322      }									\
323      (int) __sys_result; })
324 
325 #  define INTERNAL_SYSCALL_RAW2(name, arg1, arg2)			\
326   ({unsigned int __sys_result;						\
327     register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2);	\
328      {									\
329        register int _nr __asm__ ("r7");					\
330        register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1");		\
331        _a1 = _tmp_arg1, _a2 = _tmp_arg2;				\
332        _nr = name;							\
333        __asm__ __volatile__ ("trap  0 \n\t"				\
334 			     : "=r" (_a1)				\
335 			     : "r" (_nr), "r" (_a1), "r" (_a2)		\
336 			     : "memory");				\
337 	       __sys_result = _a1;					\
338      }									\
339      (int) __sys_result; })
340 
341 #  define INTERNAL_SYSCALL_RAW3(name, arg1, arg2, arg3)			\
342   ({unsigned int __sys_result;						\
343     register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2);	\
344     register int _tmp_arg3 = (int)(arg3);				\
345      {									\
346        register int _nr __asm__ ("r7");					\
347        register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1");		\
348        register int _a3 __asm__ ("a2");					\
349        _a1 = _tmp_arg1;							\
350        _a2 = _tmp_arg2;							\
351        _a3 = _tmp_arg3;							\
352        _nr = name;							\
353        __asm__ __volatile__ ("trap  0 \n\t"				\
354 			     : "=r" (_a1)				\
355 			     : "r" (_nr), "r" (_a1), "r" (_a2),		\
356 			       "r" (_a3)				\
357 			     : "memory");				\
358 	       __sys_result = _a1;					\
359      }									\
360      (int) __sys_result; })
361 
362 #  define INTERNAL_SYSCALL_RAW4(name, arg1, arg2, arg3, arg4)		\
363   ({unsigned int __sys_result;						\
364     register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2);	\
365     register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4);	\
366      {									\
367        register int _nr __asm__ ("r7");					\
368        register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1");		\
369        register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3");		\
370        _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3;		\
371        _a4 = _tmp_arg4;							\
372        _nr = name;							\
373        __asm__ __volatile__ ("trap  0 \n\t"				\
374 			     : "=r" (_a1)				\
375 			     : "r" (_nr), "r" (_a1), "r" (_a2),		\
376 			       "r" (_a3), "r" (_a4)			\
377 			     : "memory");				\
378 	       __sys_result = _a1;					\
379      }									\
380      (int) __sys_result; })
381 
382 #  define INTERNAL_SYSCALL_RAW5(name, arg1, arg2, arg3, arg4,		\
383 			      arg5)					\
384   ({unsigned int __sys_result;						\
385     register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2);	\
386     register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4);	\
387     register int _tmp_arg5 = (int)(arg5);				\
388      {									\
389        register int _nr __asm__ ("r7");					\
390        register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1");		\
391        register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3");		\
392        register int _a5 __asm__ ("r4");					\
393        _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3;		\
394        _a4 = _tmp_arg4, _a5 = _tmp_arg5;				\
395        _nr = name;							\
396        __asm__ __volatile__ ("trap  0 \n\t"				\
397 			     : "=r" (_a1)				\
398 			     : "r" (_nr), "r" (_a1), "r" (_a2),		\
399 			       "r" (_a3), "r" (_a4), "r" (_a5)		\
400 			     : "memory");				\
401 	       __sys_result = _a1;					\
402      }									\
403      (int) __sys_result; })
404 
405 #  define INTERNAL_SYSCALL_RAW6(name, arg1, arg2, arg3, arg4,		\
406 			      arg5, arg6)				\
407   ({unsigned int __sys_result;						\
408     register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2);	\
409     register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4);	\
410     register int _tmp_arg5 = (int)(arg5), _tmp_arg6 = (int)(arg6);	\
411      {									\
412        register int _nr __asm__ ("r7");					\
413        register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1");		\
414        register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3");		\
415        register int _a5 __asm__ ("r4"), _a6 __asm__ ("r5");		\
416        _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3;		\
417        _a4 = _tmp_arg4, _a5 = _tmp_arg5, _a6 = _tmp_arg6;		\
418        _nr = name;							\
419        __asm__ __volatile__ ("trap  0 \n\t"				\
420 			     : "=r" (_a1)				\
421 			     : "r" (_nr), "r" (_a1), "r" (_a2),		\
422 			       "r" (_a3), "r" (_a4), "r" (_a5),		\
423 			       "r" (_a6)				\
424 			     : "memory");				\
425 	       __sys_result = _a1;					\
426      }									\
427      (int) __sys_result; })
428 
429 #  define INTERNAL_SYSCALL_RAW7(name, arg1, arg2, arg3, arg4,		\
430 			      arg5, arg6, arg7)				\
431   ({unsigned int __sys_result;						\
432     register int _tmp_arg1 = (int)(arg1), _tmp_arg2 = (int)(arg2);	\
433     register int _tmp_arg3 = (int)(arg3), _tmp_arg4 = (int)(arg4);	\
434     register int _tmp_arg5 = (int)(arg5), _tmp_arg6 = (int)(arg6);	\
435     register int _tmp_arg7 = (int)(arg7);				\
436      {									\
437        register int _nr __asm__ ("r7");					\
438        register int _a1 __asm__ ("a0"), _a2 __asm__ ("a1");		\
439        register int _a3 __asm__ ("a2"), _a4 __asm__ ("a3");		\
440        register int _a5 __asm__ ("r4"), _a6 __asm__ ("r5");		\
441        register int _a7 __asm__ ("r6");					\
442        _a1 = _tmp_arg1, _a2 = _tmp_arg2, _a3 = _tmp_arg3;		\
443        _a4 = _tmp_arg4, _a5 = _tmp_arg5, _a6 = _tmp_arg6;		\
444        _a7 = _tmp_arg7;							\
445        _nr = name;							\
446        __asm__ __volatile__ ("trap  0 \n\t"				\
447 			     : "=r" (_a1)				\
448 			     : "r" (_nr), "r" (_a1), "r" (_a2),		\
449 			       "r" (_a3), "r" (_a4), "r" (_a5),		\
450 			       "r" (_a6), "r" (_a7)			\
451 			     : "memory");				\
452 	       __sys_result = _a1;					\
453      }									\
454      (int) __sys_result; })
455 
456 # undef INTERNAL_SYSCALL
457 # define INTERNAL_SYSCALL(name, nr, args...)			\
458   INTERNAL_SYSCALL_RAW##nr(SYS_ify(name), args)
459 
460 # undef INTERNAL_SYSCALL_NCS
461 # define INTERNAL_SYSCALL_NCS(number, nr, args...)		\
462   INTERNAL_SYSCALL_RAW##nr (number, args)
463 
464 #undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
465 #define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
466 
467 #endif /* __ASSEMBLER__ */
468 
469 /* Pointer mangling support.  */
470 #if (IS_IN (rtld) \
471      || (!defined SHARED && (IS_IN (libc) || IS_IN (libpthread))))
472 # ifdef __ASSEMBLER__
473 #  define PTR_MANGLE(dst, src, guard)			\
474 	grs	t0, 1f;					\
475 1:							\
476 	lrw	guard, 1b@GOTPC;			\
477 	addu	t0, guard;				\
478 	lrw	guard, __pointer_chk_guard_local@GOT;	\
479 	ldr.w	guard, (t0, guard << 0);		\
480 	ldw	guard, (guard, 0);			\
481 	xor	dst, src, guard;
482 #  define PTR_DEMANGLE(dst, src, guard) PTR_MANGLE (dst, src, guard)
483 #  define PTR_MANGLE2(dst, src, guard) \
484 	xor	dst, src, guard
485 #  define PTR_DEMANGLE2(dst, src, guard) PTR_MANGLE2 (dst, src, guard)
486 # else
487 extern uintptr_t __pointer_chk_guard_local;
488 #  define PTR_MANGLE(var) \
489   (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local)
490 #  define PTR_DEMANGLE(var) PTR_MANGLE (var)
491 # endif
492 #else
493 # ifdef __ASSEMBLER__
494 #  define PTR_MANGLE(dst, src, guard)		\
495 	grs	t0, 1f;				\
496 1:						\
497 	lrw	guard, 1b@GOTPC;		\
498 	addu	t0, guard;			\
499 	lrw	guard, __pointer_chk_guard@GOT;	\
500 	ldr.w	guard, (t0, guard << 0);	\
501 	ldw	guard, (guard, 0);		\
502 	xor	dst, src, guard;
503 #  define PTR_DEMANGLE(dst, src, guard) PTR_MANGLE (dst, src, guard)
504 #  define PTR_MANGLE2(dst, src, guard) \
505 	xor	dst, src, guard
506 #  define PTR_DEMANGLE2(dst, src, guard) PTR_MANGLE2 (dst, src, guard)
507 # else
508 extern uintptr_t __pointer_chk_guard;
509 #  define PTR_MANGLE(var) \
510   (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard)
511 #  define PTR_DEMANGLE(var) PTR_MANGLE (var)
512 # endif
513 #endif
514 
515 #endif /* linux/csky/sysdep.h */
516