master
  1/* Assembly macros for C-SKY.
  2   Copyright (C) 2018-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_CSKY_SYSDEP_H
 20#define _LINUX_CSKY_SYSDEP_H 1
 21
 22/* There is some commonality.  */
 23#include <sysdeps/unix/sysv/linux/sysdep.h>
 24#include <sysdeps/csky/sysdep.h>
 25#include <sysdeps/unix/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;			\
 801:					\
 81	rts
 82#  else
 83#   define PSEUDO_RET			\
 84	btsti	a0, 31;			\
 85	bf	1f;			\
 86	jmpi	SYSCALL_ERROR;		\
 871:					\
 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;			\
1031:					\
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#endif /* linux/csky/sysdep.h */