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_MIPS32_SYSDEP_H
      19  #define _LINUX_MIPS_MIPS32_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/mips32/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  #ifdef __PIC__
      40  # undef SYSCALL_ERROR_LABEL
      41  # define SYSCALL_ERROR_LABEL 99b
      42  #endif
      43  
      44  #else   /* ! __ASSEMBLER__ */
      45  
      46  #undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
      47  #define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
      48  
      49  /* Note that the original Linux syscall restart convention required the
      50     instruction immediately preceding SYSCALL to initialize $v0 with the
      51     syscall number.  Then if a restart triggered, $v0 would have been
      52     clobbered by the syscall interrupted, and needed to be reinititalized.
      53     The kernel would decrement the PC by 4 before switching back to the
      54     user mode so that $v0 had been reloaded before SYSCALL was executed
      55     again.  This implied the place $v0 was loaded from must have been
      56     preserved across a syscall, e.g. an immediate, static register, stack
      57     slot, etc.
      58  
      59     The convention was relaxed in Linux with a change applied to the kernel
      60     GIT repository as commit 96187fb0bc30cd7919759d371d810e928048249d, that
      61     first appeared in the 2.6.36 release.  Since then the kernel has had
      62     code that reloads $v0 upon syscall restart and resumes right at the
      63     SYSCALL instruction, so no special arrangement is needed anymore.
      64  
      65     For backwards compatibility with existing kernel binaries we support
      66     the old convention by choosing the instruction preceding SYSCALL
      67     carefully.  This also means we have to force a 32-bit encoding of the
      68     microMIPS MOVE instruction if one is used.  */
      69  
      70  #ifdef __mips_micromips
      71  # define MOVE32 "move32"
      72  #else
      73  # define MOVE32 "move"
      74  #endif
      75  
      76  #undef INTERNAL_SYSCALL
      77  #undef INTERNAL_SYSCALL_NCS
      78  
      79  #define __nomips16 __attribute__ ((nomips16))
      80  
      81  union __mips_syscall_return
      82    {
      83      long long int val;
      84      struct
      85        {
      86  	long int v0;
      87  	long int v1;
      88        }
      89      reg;
      90    };
      91  
      92  #ifdef __mips16
      93  /* There's no MIPS16 syscall instruction, so we go through out-of-line
      94     standard MIPS wrappers.  These do use inline snippets below though,
      95     through INTERNAL_SYSCALL_MIPS16.  Spilling the syscall number to
      96     memory gives the best code in that case, avoiding the need to save
      97     and restore a static register.  */
      98  
      99  # include <mips16-syscall.h>
     100  
     101  # define INTERNAL_SYSCALL(name, nr, args...)				\
     102  	INTERNAL_SYSCALL_NCS (SYS_ify (name), nr, args)
     103  
     104  # define INTERNAL_SYSCALL_NCS(number, nr, args...)			\
     105  ({									\
     106  	union __mips_syscall_return _sc_ret;				\
     107  	_sc_ret.val = __mips16_syscall##nr (args, number);		\
     108  	_sc_ret.reg.v0;							\
     109  })
     110  
     111  # define INTERNAL_SYSCALL_MIPS16(number, err, nr, args...)		\
     112  	internal_syscall##nr ("lw\t%0, %2\n\t",				\
     113  			      "R" (number),				\
     114  			      number, err, args)
     115  
     116  #else /* !__mips16 */
     117  # define INTERNAL_SYSCALL(name, nr, args...)				\
     118  	internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t",	\
     119  			      "IK" (SYS_ify (name)),			\
     120  			      SYS_ify (name), err, args)
     121  
     122  # define INTERNAL_SYSCALL_NCS(number, nr, args...)			\
     123  	internal_syscall##nr (MOVE32 "\t%0, %2\n\t",			\
     124  			      "r" (__s0),				\
     125  			      number, err, args)
     126  
     127  #endif /* !__mips16 */
     128  
     129  #define internal_syscall0(v0_init, input, number, err, dummy...)	\
     130  ({									\
     131  	long int _sys_result;						\
     132  									\
     133  	{								\
     134  	register long int __s0 asm ("$16") __attribute__ ((unused))	\
     135  	  = (number);							\
     136  	register long int __v0 asm ("$2");				\
     137  	register long int __a3 asm ("$7");				\
     138  	__asm__ volatile (						\
     139  	".set\tnoreorder\n\t"						\
     140  	v0_init								\
     141  	"syscall\n\t"							\
     142  	".set reorder"							\
     143  	: "=r" (__v0), "=r" (__a3)					\
     144  	: input								\
     145  	: __SYSCALL_CLOBBERS);						\
     146  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     147  	}								\
     148  	_sys_result;							\
     149  })
     150  
     151  #define internal_syscall1(v0_init, input, number, err, arg1)		\
     152  ({									\
     153  	long int _sys_result;						\
     154  									\
     155  	{								\
     156  	long int _arg1 = (long int) (arg1);				\
     157  	register long int __s0 asm ("$16") __attribute__ ((unused))	\
     158  	  = (number);							\
     159  	register long int __v0 asm ("$2");				\
     160  	register long int __a0 asm ("$4") = _arg1;			\
     161  	register long int __a3 asm ("$7");				\
     162  	__asm__ volatile (						\
     163  	".set\tnoreorder\n\t"						\
     164  	v0_init								\
     165  	"syscall\n\t"							\
     166  	".set reorder"							\
     167  	: "=r" (__v0), "=r" (__a3)					\
     168  	: input, "r" (__a0)						\
     169  	: __SYSCALL_CLOBBERS);						\
     170  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     171  	}								\
     172  	_sys_result;							\
     173  })
     174  
     175  #define internal_syscall2(v0_init, input, number, err, arg1, arg2)	\
     176  ({									\
     177  	long int _sys_result;						\
     178  									\
     179  	{								\
     180  	long int _arg1 = (long int) (arg1);				\
     181  	long int _arg2 = (long int) (arg2);				\
     182  	register long int __s0 asm ("$16") __attribute__ ((unused))	\
     183  	  = (number);							\
     184  	register long int __v0 asm ("$2");				\
     185  	register long int __a0 asm ("$4") = _arg1;			\
     186  	register long int __a1 asm ("$5") = _arg2;			\
     187  	register long int __a3 asm ("$7");				\
     188  	__asm__ volatile (						\
     189  	".set\tnoreorder\n\t"						\
     190  	v0_init								\
     191  	"syscall\n\t"							\
     192  	".set\treorder"							\
     193  	: "=r" (__v0), "=r" (__a3)					\
     194  	: input, "r" (__a0), "r" (__a1)					\
     195  	: __SYSCALL_CLOBBERS);						\
     196  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     197  	}								\
     198  	_sys_result;							\
     199  })
     200  
     201  #define internal_syscall3(v0_init, input, number, err,			\
     202  			  arg1, arg2, arg3)				\
     203  ({									\
     204  	long int _sys_result;						\
     205  									\
     206  	{								\
     207  	long int _arg1 = (long int) (arg1);				\
     208  	long int _arg2 = (long int) (arg2);				\
     209  	long int _arg3 = (long int) (arg3);				\
     210  	register long int __s0 asm ("$16") __attribute__ ((unused))	\
     211  	  = (number);							\
     212  	register long int __v0 asm ("$2");				\
     213  	register long int __a0 asm ("$4") = _arg1;			\
     214  	register long int __a1 asm ("$5") = _arg2;			\
     215  	register long int __a2 asm ("$6") = _arg3;			\
     216  	register long int __a3 asm ("$7");				\
     217  	__asm__ volatile (						\
     218  	".set\tnoreorder\n\t"						\
     219  	v0_init								\
     220  	"syscall\n\t"							\
     221  	".set\treorder"							\
     222  	: "=r" (__v0), "=r" (__a3)					\
     223  	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\
     224  	: __SYSCALL_CLOBBERS);						\
     225  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     226  	}								\
     227  	_sys_result;							\
     228  })
     229  
     230  #define internal_syscall4(v0_init, input, number, err,			\
     231  			  arg1, arg2, arg3, arg4)			\
     232  ({									\
     233  	long int _sys_result;						\
     234  									\
     235  	{								\
     236  	long int _arg1 = (long int) (arg1);				\
     237  	long int _arg2 = (long int) (arg2);				\
     238  	long int _arg3 = (long int) (arg3);				\
     239  	long int _arg4 = (long int) (arg4);				\
     240  	register long int __s0 asm ("$16") __attribute__ ((unused))	\
     241  	  = (number);							\
     242  	register long int __v0 asm ("$2");				\
     243  	register long int __a0 asm ("$4") = _arg1;			\
     244  	register long int __a1 asm ("$5") = _arg2;			\
     245  	register long int __a2 asm ("$6") = _arg3;			\
     246  	register long int __a3 asm ("$7") = _arg4;			\
     247  	__asm__ volatile (						\
     248  	".set\tnoreorder\n\t"						\
     249  	v0_init								\
     250  	"syscall\n\t"							\
     251  	".set\treorder"							\
     252  	: "=r" (__v0), "+r" (__a3)					\
     253  	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\
     254  	: __SYSCALL_CLOBBERS);						\
     255  	_sys_result = __a3 != 0 ? -__v0 : __v0;				\
     256  	}								\
     257  	_sys_result;							\
     258  })
     259  
     260  /* Standalone MIPS wrappers used for 5, 6, and 7 argument syscalls,
     261     which require stack arguments.  We rely on the compiler arranging
     262     wrapper's arguments according to the MIPS o32 function calling
     263     convention, which is reused by syscalls, except for the syscall
     264     number passed and the error flag returned (taken care of in the
     265     wrapper called).  This relieves us from relying on non-guaranteed
     266     compiler specifics required for the stack arguments to be pushed,
     267     which would be the case if these syscalls were inlined.  */
     268  
     269  long long int __nomips16 __mips_syscall5 (long int arg1, long int arg2,
     270  					  long int arg3, long int arg4,
     271  					  long int arg5,
     272  					  long int number);
     273  libc_hidden_proto (__mips_syscall5, nomips16)
     274  
     275  #define internal_syscall5(v0_init, input, number, err,			\
     276  			  arg1, arg2, arg3, arg4, arg5)			\
     277  ({									\
     278  	union __mips_syscall_return _sc_ret;				\
     279  	_sc_ret.val = __mips_syscall5 ((long int) (arg1),		\
     280  				       (long int) (arg2),		\
     281  				       (long int) (arg3),		\
     282  				       (long int) (arg4),		\
     283  				       (long int) (arg5),		\
     284  				       (long int) (number));		\
     285  	_sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0;		\
     286  })
     287  
     288  long long int __nomips16 __mips_syscall6 (long int arg1, long int arg2,
     289  					  long int arg3, long int arg4,
     290  					  long int arg5, long int arg6,
     291  					  long int number);
     292  libc_hidden_proto (__mips_syscall6, nomips16)
     293  
     294  #define internal_syscall6(v0_init, input, number, err,			\
     295  			  arg1, arg2, arg3, arg4, arg5, arg6)		\
     296  ({									\
     297  	union __mips_syscall_return _sc_ret;				\
     298  	_sc_ret.val = __mips_syscall6 ((long int) (arg1),		\
     299  				       (long int) (arg2),		\
     300  				       (long int) (arg3),		\
     301  				       (long int) (arg4),		\
     302  				       (long int) (arg5),		\
     303  				       (long int) (arg6),		\
     304  				       (long int) (number));		\
     305  	_sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0;		\
     306  })
     307  
     308  long long int __nomips16 __mips_syscall7 (long int arg1, long int arg2,
     309  					  long int arg3, long int arg4,
     310  					  long int arg5, long int arg6,
     311  					  long int arg7,
     312  					  long int number);
     313  libc_hidden_proto (__mips_syscall7, nomips16)
     314  
     315  #define internal_syscall7(v0_init, input, number, err,			\
     316  			  arg1, arg2, arg3, arg4, arg5, arg6, arg7)	\
     317  ({									\
     318  	union __mips_syscall_return _sc_ret;				\
     319  	_sc_ret.val = __mips_syscall7 ((long int) (arg1),		\
     320  				       (long int) (arg2),		\
     321  				       (long int) (arg3),		\
     322  				       (long int) (arg4),		\
     323  				       (long int) (arg5),		\
     324  				       (long int) (arg6),		\
     325  				       (long int) (arg7),		\
     326  				       (long int) (number));		\
     327  	_sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0;		\
     328  })
     329  
     330  #if __mips_isa_rev >= 6
     331  # define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
     332  	 "$14", "$15", "$24", "$25", "memory"
     333  #else
     334  # define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
     335  	 "$14", "$15", "$24", "$25", "hi", "lo", "memory"
     336  #endif
     337  
     338  #endif /* __ASSEMBLER__ */
     339  
     340  #endif /* linux/mips/mips32/sysdep.h */