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_ALPHA_SYSDEP_H
      19  #define _LINUX_ALPHA_SYSDEP_H 1
      20  
      21  /* There is some commonality.  */
      22  #include <sysdeps/unix/sysv/linux/sysdep.h>
      23  #include <sysdeps/unix/sysdep.h>
      24  #include <dl-sysdep.h>         /* Defines RTLD_PRIVATE_ERRNO.  */
      25  
      26  #include <tls.h>
      27  
      28  /* For Linux we can use the system call table in the header file
      29  	/usr/include/asm/unistd.h
      30     of the kernel.  But these symbols do not follow the SYS_* syntax
      31     so we have to redefine the `SYS_ify' macro here.  */
      32  #undef SYS_ify
      33  #define SYS_ify(syscall_name)	__NR_##syscall_name
      34  
      35  #ifdef __ASSEMBLER__
      36  #include <asm/pal.h>
      37  #include <alpha/regdef.h>
      38  
      39  #define __LABEL(x)	x##:
      40  
      41  #define LEAF(name, framesize)			\
      42    .globl name;					\
      43    .align 4;					\
      44    .ent name, 0;					\
      45    __LABEL(name)					\
      46    .frame sp, framesize, ra
      47  
      48  #define ENTRY(name)				\
      49    .globl name;					\
      50    .align 4;					\
      51    .ent name, 0;					\
      52    __LABEL(name)					\
      53    .frame sp, 0, ra
      54  
      55  /* Mark the end of function SYM.  */
      56  #undef END
      57  #define END(sym)	.end sym
      58  
      59  #ifdef PROF
      60  # define PSEUDO_PROF				\
      61  	.set noat;				\
      62  	lda	AT, _mcount;			\
      63  	jsr	AT, (AT), _mcount;		\
      64  	.set at
      65  #else
      66  # define PSEUDO_PROF
      67  #endif
      68  
      69  #ifdef PROF
      70  # define PSEUDO_PROLOGUE			\
      71  	.frame sp, 0, ra;			\
      72  	ldgp	gp,0(pv);			\
      73  	PSEUDO_PROF;				\
      74  	.prologue 1
      75  #elif defined PIC
      76  # define PSEUDO_PROLOGUE			\
      77  	.frame sp, 0, ra;			\
      78  	.prologue 0
      79  #else
      80  # define PSEUDO_PROLOGUE			\
      81  	.frame sp, 0, ra;			\
      82  	ldgp	gp,0(pv);			\
      83  	.prologue 1
      84  #endif /* PROF */
      85  
      86  #ifdef PROF
      87  # define USEPV_PROF	std
      88  #else
      89  # define USEPV_PROF	no
      90  #endif
      91  
      92  #undef SYSCALL_ERROR_LABEL
      93  #if RTLD_PRIVATE_ERRNO
      94  # define SYSCALL_ERROR_LABEL	$syscall_error
      95  # define SYSCALL_ERROR_HANDLER			\
      96  $syscall_error:					\
      97  	stl	v0, rtld_errno(gp)	!gprel;	\
      98  	lda	v0, -1;				\
      99  	ret
     100  # define SYSCALL_ERROR_FALLTHRU
     101  #elif defined(PIC)
     102  # define SYSCALL_ERROR_LABEL		__syscall_error !samegp
     103  # define SYSCALL_ERROR_HANDLER
     104  # define SYSCALL_ERROR_FALLTHRU		br SYSCALL_ERROR_LABEL
     105  #else
     106  # define SYSCALL_ERROR_LABEL		$syscall_error
     107  # define SYSCALL_ERROR_HANDLER			\
     108  $syscall_error:					\
     109  	jmp $31, __syscall_error
     110  # define SYSCALL_ERROR_FALLTHRU
     111  #endif /* RTLD_PRIVATE_ERRNO */
     112  
     113  /* Overridden by specific syscalls.  */
     114  #undef PSEUDO_PREPARE_ARGS
     115  #define PSEUDO_PREPARE_ARGS	/* Nothing.  */
     116  
     117  #define PSEUDO(name, syscall_name, args)	\
     118  	.globl name;				\
     119  	.align 4;				\
     120  	.ent name,0;				\
     121  __LABEL(name)					\
     122  	PSEUDO_PROLOGUE;			\
     123  	PSEUDO_PREPARE_ARGS			\
     124  	lda	v0, SYS_ify(syscall_name);	\
     125  	call_pal PAL_callsys;			\
     126  	bne	a3, SYSCALL_ERROR_LABEL
     127  
     128  #undef PSEUDO_END
     129  #define PSEUDO_END(sym)				\
     130  	SYSCALL_ERROR_HANDLER;			\
     131  	END(sym)
     132  
     133  #define PSEUDO_NOERRNO(name, syscall_name, args)	\
     134  	.globl name;					\
     135  	.align 4;					\
     136  	.ent name,0;					\
     137  __LABEL(name)						\
     138  	PSEUDO_PROLOGUE;				\
     139  	PSEUDO_PREPARE_ARGS				\
     140  	lda	v0, SYS_ify(syscall_name);		\
     141  	call_pal PAL_callsys;
     142  
     143  #undef PSEUDO_END_NOERRNO
     144  #define PSEUDO_END_NOERRNO(sym)  END(sym)
     145  
     146  #define ret_NOERRNO ret
     147  
     148  #define PSEUDO_ERRVAL(name, syscall_name, args)	\
     149  	.globl name;					\
     150  	.align 4;					\
     151  	.ent name,0;					\
     152  __LABEL(name)						\
     153  	PSEUDO_PROLOGUE;				\
     154  	PSEUDO_PREPARE_ARGS				\
     155  	lda	v0, SYS_ify(syscall_name);		\
     156  	call_pal PAL_callsys;
     157  
     158  #undef PSEUDO_END_ERRVAL
     159  #define PSEUDO_END_ERRVAL(sym)  END(sym)
     160  
     161  #define ret_ERRVAL ret
     162  
     163  #define r0	v0
     164  #define r1	a4
     165  
     166  #define MOVE(x,y)	mov x,y
     167  
     168  #else /* !ASSEMBLER */
     169  
     170  #define INTERNAL_SYSCALL(name, nr, args...) \
     171  	internal_syscall##nr(__NR_##name, args)
     172  
     173  #define INTERNAL_SYSCALL_NCS(name, nr, args...) \
     174  	internal_syscall##nr(name, args)
     175  
     176  /* The normal Alpha calling convention sign-extends 32-bit quantties
     177     no matter what the "real" sign of the 32-bit type.  We want to
     178     preserve that when filling in values for the kernel.  */
     179  #define syscall_promote(arg) \
     180    (sizeof (arg) == 4 ? (long int)(int)(long int)(arg) : (long int)(arg))
     181  
     182  #define internal_syscall_clobbers				\
     183  	"$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",	\
     184  	"$22", "$23", "$24", "$25", "$27", "$28", "memory"
     185  
     186  /* It is moderately important optimization-wise to limit the lifetime
     187     of the hard-register variables as much as possible.  Thus we copy
     188     in/out as close to the asm as possible.  */
     189  
     190  #define internal_syscall0(name, args...)			\
     191  ({								\
     192  	register long int _sc_19 __asm__("$19");		\
     193  	register long int _sc_0 = name;				\
     194  	__asm__ __volatile__					\
     195  	  ("callsys # %0 %1 <= %2"				\
     196  	   : "+v"(_sc_0), "=r"(_sc_19)				\
     197  	   : : internal_syscall_clobbers,			\
     198  	     "$16", "$17", "$18", "$20", "$21");		\
     199  	_sc_19 != 0 ? -_sc_0 : _sc_0;				\
     200  })
     201  
     202  #define internal_syscall1(name,arg1)				\
     203  ({								\
     204  	register long int _tmp_16 = syscall_promote (arg1);	\
     205  	register long int _sc_0 = name;				\
     206  	register long int _sc_16 __asm__("$16") = _tmp_16;	\
     207  	register long int _sc_19 __asm__("$19");		\
     208  	__asm__ __volatile__					\
     209  	  ("callsys # %0 %1 <= %2 %3"				\
     210  	   : "+v"(_sc_0), "=r"(_sc_19), "+r"(_sc_16)		\
     211  	   : : internal_syscall_clobbers,			\
     212  	     "$17", "$18", "$20", "$21");			\
     213  	_sc_19 != 0 ? -_sc_0 : _sc_0;				\
     214  })
     215  
     216  #define internal_syscall2(name,arg1,arg2)			\
     217  ({								\
     218  	register long int _tmp_16 = syscall_promote (arg1);	\
     219  	register long int _tmp_17 = syscall_promote (arg2);	\
     220  	register long int _sc_0 = name;				\
     221  	register long int _sc_16 __asm__("$16") = _tmp_16;	\
     222  	register long int _sc_17 __asm__("$17") = _tmp_17;	\
     223  	register long int _sc_19 __asm__("$19");		\
     224  	__asm__ __volatile__					\
     225  	  ("callsys # %0 %1 <= %2 %3 %4"			\
     226  	   : "+v"(_sc_0), "=r"(_sc_19),				\
     227  	     "+r"(_sc_16), "+r"(_sc_17)				\
     228  	   : : internal_syscall_clobbers,			\
     229  	     "$18", "$20", "$21");				\
     230  	_sc_19 != 0 ? -_sc_0 : _sc_0;				\
     231  })
     232  
     233  #define internal_syscall3(name,arg1,arg2,arg3)			\
     234  ({								\
     235  	register long int _tmp_16 = syscall_promote (arg1);	\
     236  	register long int _tmp_17 = syscall_promote (arg2);	\
     237  	register long int _tmp_18 = syscall_promote (arg3);	\
     238  	register long int _sc_0 = name;				\
     239  	register long int _sc_16 __asm__("$16") = _tmp_16;	\
     240  	register long int _sc_17 __asm__("$17") = _tmp_17;	\
     241  	register long int _sc_18 __asm__("$18") = _tmp_18;	\
     242  	register long int _sc_19 __asm__("$19");		\
     243  	__asm__ __volatile__					\
     244  	  ("callsys # %0 %1 <= %2 %3 %4 %5"			\
     245  	   : "+v"(_sc_0), "=r"(_sc_19), "+r"(_sc_16),		\
     246  	     "+r"(_sc_17), "+r"(_sc_18)				\
     247  	   : : internal_syscall_clobbers, "$20", "$21");	\
     248  	_sc_19 != 0 ? -_sc_0 : _sc_0;				\
     249  })
     250  
     251  #define internal_syscall4(name,arg1,arg2,arg3,arg4)		\
     252  ({								\
     253  	register long int _tmp_16 = syscall_promote (arg1);	\
     254  	register long int _tmp_17 = syscall_promote (arg2);	\
     255  	register long int _tmp_18 = syscall_promote (arg3);	\
     256  	register long int _tmp_19 = syscall_promote (arg4);	\
     257  	register long int _sc_0 = name;				\
     258  	register long int _sc_16 __asm__("$16") = _tmp_16;	\
     259  	register long int _sc_17 __asm__("$17") = _tmp_17;	\
     260  	register long int _sc_18 __asm__("$18") = _tmp_18;	\
     261  	register long int _sc_19 __asm__("$19") = _tmp_19;	\
     262  	__asm__ __volatile__					\
     263  	  ("callsys # %0 %1 <= %2 %3 %4 %5 %6"			\
     264  	   : "+v"(_sc_0), "+r"(_sc_19), "+r"(_sc_16),		\
     265  	     "+r"(_sc_17), "+r"(_sc_18)				\
     266  	   : : internal_syscall_clobbers, "$20", "$21");	\
     267  	_sc_19 != 0 ? -_sc_0 : _sc_0;				\
     268  })
     269  
     270  #define internal_syscall5(name,arg1,arg2,arg3,arg4,arg5)	\
     271  ({								\
     272  	register long int _tmp_16 = syscall_promote (arg1);	\
     273  	register long int _tmp_17 = syscall_promote (arg2);	\
     274  	register long int _tmp_18 = syscall_promote (arg3);	\
     275  	register long int _tmp_19 = syscall_promote (arg4);	\
     276  	register long int _tmp_20 = syscall_promote (arg5);	\
     277  	register long int _sc_0 = name;				\
     278  	register long int _sc_16 __asm__("$16") = _tmp_16;	\
     279  	register long int _sc_17 __asm__("$17") = _tmp_17;	\
     280  	register long int _sc_18 __asm__("$18") = _tmp_18;	\
     281  	register long int _sc_19 __asm__("$19") = _tmp_19;	\
     282  	register long int _sc_20 __asm__("$20") = _tmp_20;	\
     283  	__asm__ __volatile__					\
     284  	  ("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7"		\
     285  	   : "+v"(_sc_0), "+r"(_sc_19), "+r"(_sc_16),		\
     286  	     "+r"(_sc_17), "+r"(_sc_18), "+r"(_sc_20)		\
     287  	   : : internal_syscall_clobbers, "$21");		\
     288  	_sc_19 != 0 ? -_sc_0 : _sc_0;				\
     289  })
     290  
     291  #define internal_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6)	\
     292  ({								\
     293  	register long int _tmp_16 = syscall_promote (arg1);	\
     294  	register long int _tmp_17 = syscall_promote (arg2);	\
     295  	register long int _tmp_18 = syscall_promote (arg3);	\
     296  	register long int _tmp_19 = syscall_promote (arg4);	\
     297  	register long int _tmp_20 = syscall_promote (arg5);	\
     298  	register long int _tmp_21 = syscall_promote (arg6);	\
     299  	register long int _sc_0 = name;				\
     300  	register long int _sc_16 __asm__("$16") = _tmp_16;	\
     301  	register long int _sc_17 __asm__("$17") = _tmp_17;	\
     302  	register long int _sc_18 __asm__("$18") = _tmp_18;	\
     303  	register long int _sc_19 __asm__("$19") = _tmp_19;	\
     304  	register long int _sc_20 __asm__("$20") = _tmp_20;	\
     305  	register long int _sc_21 __asm__("$21") = _tmp_21;	\
     306  	__asm__ __volatile__					\
     307  	  ("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7 %8"		\
     308  	   : "+v"(_sc_0), "+r"(_sc_19), "+r"(_sc_16),		\
     309  	     "+r"(_sc_17), "+r"(_sc_18), "+r"(_sc_20),		\
     310  	     "+r"(_sc_21)					\
     311  	   : : internal_syscall_clobbers);			\
     312  	_sc_19 != 0 ? -_sc_0 : _sc_0;				\
     313  })
     314  #endif /* ASSEMBLER */
     315  
     316  #endif /* _LINUX_ALPHA_SYSDEP_H  */