1  /* Copyright (C) 1992-2023 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 safely
      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  #endif /* linux/sh/sysdep.h */