1  /* Copyright (C) 2000-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_MIPS_SYSDEP_H
      19  #define _LINUX_MIPS_SYSDEP_H 1
      20  
      21  /* There is some commonality.  */
      22  #include <sysdeps/unix/sysv/linux/mips/sysdep.h>
      23  #include <sysdeps/unix/sysv/linux/sysdep.h>
      24  #include <sysdeps/unix/mips/mips64/sysdep.h>
      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  
      37  /* We don't want the label for the error handler to be visible in the symbol
      38     table when we define it here.  */
      39  # undef SYSCALL_ERROR_LABEL
      40  # define SYSCALL_ERROR_LABEL 99b
      41  
      42  #else   /* ! __ASSEMBLER__ */
      43  
      44  #undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
      45  #define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
      46  
      47  #if _MIPS_SIM == _ABIN32
      48  /* Convert X to a long long, without losing any bits if it is one
      49     already or warning if it is a 32-bit pointer.  */
      50  # define ARGIFY(X) ((long long int) (__typeof__ ((X) - (X))) (X))
      51  typedef long long int __syscall_arg_t;
      52  #else
      53  # define ARGIFY(X) ((long int) (X))
      54  typedef long int __syscall_arg_t;
      55  #endif
      56  
      57  /* Note that the original Linux syscall restart convention required the
      58     instruction immediately preceding SYSCALL to initialize $v0 with the
      59     syscall number.  Then if a restart triggered, $v0 would have been
      60     clobbered by the syscall interrupted, and needed to be reinititalized.
      61     The kernel would decrement the PC by 4 before switching back to the
      62     user mode so that $v0 had been reloaded before SYSCALL was executed
      63     again.  This implied the place $v0 was loaded from must have been
      64     preserved across a syscall, e.g. an immediate, static register, stack
      65     slot, etc.
      66  
      67     The convention was relaxed in Linux with a change applied to the kernel
      68     GIT repository as commit 96187fb0bc30cd7919759d371d810e928048249d, that
      69     first appeared in the 2.6.36 release.  Since then the kernel has had
      70     code that reloads $v0 upon syscall restart and resumes right at the
      71     SYSCALL instruction, so no special arrangement is needed anymore.
      72  
      73     For backwards compatibility with existing kernel binaries we support
      74     the old convention by choosing the instruction preceding SYSCALL
      75     carefully.  This also means we have to force a 32-bit encoding of the
      76     microMIPS MOVE instruction if one is used.  */
      77  
      78  #ifdef __mips_micromips
      79  # define MOVE32 "move32"
      80  #else
      81  # define MOVE32 "move"
      82  #endif
      83  
      84  #undef INTERNAL_SYSCALL
      85  #define INTERNAL_SYSCALL(name, nr, args...)			\
      86  	internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t",	\
      87  			      "IK" (SYS_ify (name)),			\
      88  			      0, args)
      89  
      90  #undef INTERNAL_SYSCALL_NCS
      91  #define INTERNAL_SYSCALL_NCS(number, nr, args...)			\
      92  	internal_syscall##nr (MOVE32 "\t%0, %2\n\t",			\
      93  			      "r" (__s0),				\
      94  			      number, args)
      95  
      96  #define internal_syscall0(v0_init, input, number, dummy...)	\
      97  ({									\
      98  	long int _sys_result;						\
      99  									\
     100  	{								\
     101  	register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\
     102  	  = (number);							\
     103  	register __syscall_arg_t __v0 asm ("$2");			\
     104  	register __syscall_arg_t __a3 asm ("$7");			\
     105  	__asm__ volatile (						\
     106  	".set\tnoreorder\n\t"						\
     107  	v0_init								\
     108  	"syscall\n\t"							\
     109  	".set reorder"							\
     110  	: "=r" (__v0), "=r" (__a3)					\
     111  	: input								\
     112  	: __SYSCALL_CLOBBERS);						\
     113  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     114  	}								\
     115  	_sys_result;							\
     116  })
     117  
     118  #define internal_syscall1(v0_init, input, number, arg1)		\
     119  ({									\
     120  	long int _sys_result;						\
     121  									\
     122  	{								\
     123  	__syscall_arg_t _arg1 = ARGIFY (arg1);				\
     124  	register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\
     125  	  = (number);							\
     126  	register __syscall_arg_t __v0 asm ("$2");			\
     127  	register __syscall_arg_t __a0 asm ("$4") = _arg1;		\
     128  	register __syscall_arg_t __a3 asm ("$7");			\
     129  	__asm__ volatile (						\
     130  	".set\tnoreorder\n\t"						\
     131  	v0_init								\
     132  	"syscall\n\t"							\
     133  	".set reorder"							\
     134  	: "=r" (__v0), "=r" (__a3)					\
     135  	: input, "r" (__a0)						\
     136  	: __SYSCALL_CLOBBERS);						\
     137  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     138  	}								\
     139  	_sys_result;							\
     140  })
     141  
     142  #define internal_syscall2(v0_init, input, number, arg1, arg2)	\
     143  ({									\
     144  	long int _sys_result;						\
     145  									\
     146  	{								\
     147  	__syscall_arg_t _arg1 = ARGIFY (arg1);				\
     148  	__syscall_arg_t _arg2 = ARGIFY (arg2);				\
     149  	register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\
     150  	  = (number);							\
     151  	register __syscall_arg_t __v0 asm ("$2");			\
     152  	register __syscall_arg_t __a0 asm ("$4") = _arg1;		\
     153  	register __syscall_arg_t __a1 asm ("$5") = _arg2;		\
     154  	register __syscall_arg_t __a3 asm ("$7");			\
     155  	__asm__ volatile (						\
     156  	".set\tnoreorder\n\t"						\
     157  	v0_init								\
     158  	"syscall\n\t"							\
     159  	".set\treorder"							\
     160  	: "=r" (__v0), "=r" (__a3)					\
     161  	: input, "r" (__a0), "r" (__a1)					\
     162  	: __SYSCALL_CLOBBERS);						\
     163  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     164  	}								\
     165  	_sys_result;							\
     166  })
     167  
     168  #define internal_syscall3(v0_init, input, number, arg1, arg2, arg3)	\
     169  ({									\
     170  	long int _sys_result;						\
     171  									\
     172  	{								\
     173  	__syscall_arg_t _arg1 = ARGIFY (arg1);				\
     174  	__syscall_arg_t _arg2 = ARGIFY (arg2);				\
     175  	__syscall_arg_t _arg3 = ARGIFY (arg3);				\
     176  	register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\
     177  	  = (number);							\
     178  	register __syscall_arg_t __v0 asm ("$2");			\
     179  	register __syscall_arg_t __a0 asm ("$4") = _arg1;		\
     180  	register __syscall_arg_t __a1 asm ("$5") = _arg2;		\
     181  	register __syscall_arg_t __a2 asm ("$6") = _arg3;		\
     182  	register __syscall_arg_t __a3 asm ("$7");			\
     183  	__asm__ volatile (						\
     184  	".set\tnoreorder\n\t"						\
     185  	v0_init								\
     186  	"syscall\n\t"							\
     187  	".set\treorder"							\
     188  	: "=r" (__v0), "=r" (__a3)					\
     189  	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\
     190  	: __SYSCALL_CLOBBERS);						\
     191  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     192  	}								\
     193  	_sys_result;							\
     194  })
     195  
     196  #define internal_syscall4(v0_init, input, number, arg1, arg2, arg3, 	\
     197  			  arg4)						\
     198  ({									\
     199  	long int _sys_result;						\
     200  									\
     201  	{								\
     202  	__syscall_arg_t _arg1 = ARGIFY (arg1);				\
     203  	__syscall_arg_t _arg2 = ARGIFY (arg2);				\
     204  	__syscall_arg_t _arg3 = ARGIFY (arg3);				\
     205  	__syscall_arg_t _arg4 = ARGIFY (arg4);				\
     206  	register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\
     207  	  = (number);							\
     208  	register __syscall_arg_t __v0 asm ("$2");			\
     209  	register __syscall_arg_t __a0 asm ("$4") = _arg1;		\
     210  	register __syscall_arg_t __a1 asm ("$5") = _arg2;		\
     211  	register __syscall_arg_t __a2 asm ("$6") = _arg3;		\
     212  	register __syscall_arg_t __a3 asm ("$7") = _arg4;		\
     213  	__asm__ volatile (						\
     214  	".set\tnoreorder\n\t"						\
     215  	v0_init								\
     216  	"syscall\n\t"							\
     217  	".set\treorder"							\
     218  	: "=r" (__v0), "+r" (__a3)					\
     219  	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\
     220  	: __SYSCALL_CLOBBERS);						\
     221  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     222  	}								\
     223  	_sys_result;							\
     224  })
     225  
     226  #define internal_syscall5(v0_init, input, number, arg1, arg2, arg3, 	\
     227  			  arg4, arg5)					\
     228  ({									\
     229  	long int _sys_result;						\
     230  									\
     231  	{								\
     232  	__syscall_arg_t _arg1 = ARGIFY (arg1);				\
     233  	__syscall_arg_t _arg2 = ARGIFY (arg2);				\
     234  	__syscall_arg_t _arg3 = ARGIFY (arg3);				\
     235  	__syscall_arg_t _arg4 = ARGIFY (arg4);				\
     236  	__syscall_arg_t _arg5 = ARGIFY (arg5);				\
     237  	register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\
     238  	  = (number);							\
     239  	register __syscall_arg_t __v0 asm ("$2");			\
     240  	register __syscall_arg_t __a0 asm ("$4") = _arg1;		\
     241  	register __syscall_arg_t __a1 asm ("$5") = _arg2;		\
     242  	register __syscall_arg_t __a2 asm ("$6") = _arg3;		\
     243  	register __syscall_arg_t __a3 asm ("$7") = _arg4;		\
     244  	register __syscall_arg_t __a4 asm ("$8") = _arg5;		\
     245  	__asm__ volatile (						\
     246  	".set\tnoreorder\n\t"						\
     247  	v0_init								\
     248  	"syscall\n\t"							\
     249  	".set\treorder"							\
     250  	: "=r" (__v0), "+r" (__a3)					\
     251  	: input, "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a4)		\
     252  	: __SYSCALL_CLOBBERS);						\
     253  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     254  	}								\
     255  	_sys_result;							\
     256  })
     257  
     258  #define internal_syscall6(v0_init, input, number, arg1, arg2, arg3, 	\
     259  			  arg4, arg5, arg6)				\
     260  ({									\
     261  	long int _sys_result;						\
     262  									\
     263  	{								\
     264  	__syscall_arg_t _arg1 = ARGIFY (arg1);				\
     265  	__syscall_arg_t _arg2 = ARGIFY (arg2);				\
     266  	__syscall_arg_t _arg3 = ARGIFY (arg3);				\
     267  	__syscall_arg_t _arg4 = ARGIFY (arg4);				\
     268  	__syscall_arg_t _arg5 = ARGIFY (arg5);				\
     269  	__syscall_arg_t _arg6 = ARGIFY (arg6);				\
     270  	register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\
     271  	  = (number);							\
     272  	register __syscall_arg_t __v0 asm ("$2");			\
     273  	register __syscall_arg_t __a0 asm ("$4") = _arg1;		\
     274  	register __syscall_arg_t __a1 asm ("$5") = _arg2;		\
     275  	register __syscall_arg_t __a2 asm ("$6") = _arg3;		\
     276  	register __syscall_arg_t __a3 asm ("$7") = _arg4;		\
     277  	register __syscall_arg_t __a4 asm ("$8") = _arg5;		\
     278  	register __syscall_arg_t __a5 asm ("$9") = _arg6;		\
     279  	__asm__ volatile (						\
     280  	".set\tnoreorder\n\t"						\
     281  	v0_init								\
     282  	"syscall\n\t"							\
     283  	".set\treorder"							\
     284  	: "=r" (__v0), "+r" (__a3)					\
     285  	: input, "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a4),	\
     286  	  "r" (__a5)							\
     287  	: __SYSCALL_CLOBBERS);						\
     288  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     289  	}								\
     290  	_sys_result;							\
     291  })
     292  
     293  #if __mips_isa_rev >= 6
     294  # define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
     295  	 "$14", "$15", "$24", "$25", "memory"
     296  #else
     297  # define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
     298  	 "$14", "$15", "$24", "$25", "hi", "lo", "memory"
     299  #endif
     300  
     301  #endif /* __ASSEMBLER__ */
     302  
     303  #endif /* linux/mips/sysdep.h */