1  /* Assembly macros for C-SKY.
       2     Copyright (C) 2018-2023 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;			\
      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  #endif /* linux/csky/sysdep.h */