This is the mail archive of the libc-ports@sources.redhat.com mailing list for the libc-ports project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][BZ #15054] MIPS: Fix syscall wrappers for syscall restart support


Hi,

 We have an issue with the INTERNAL_SYSCALL_NCS wrapper in that it does 
not respect the kernel's syscall restart convention.

 That convention requires the instruction immediately preceding SYSCALL to 
initialize $v0 with the syscall number.  Then if a restart triggers, $v0 
will have been clobbered by the syscall interrupted, and needs to be 
reinititalized.  The kernel will decrement the PC by 4 before switching 
back to the user mode so that $v0 has been reloaded before SYSCALL is 
executed again.  This implies the place $v0 is loaded from must be 
preserved across a syscall, e.g. an immediate, static register, stack 
slot, etc.

 We use two wrapper macros to dispatch syscalls to the relevant pieces of 
code: INTERNAL_SYSCALL and INTERNAL_SYSCALL_NCS.  They both ultimately 
cause a piece of inline assembly to be emitted.  In the former case the 
piece starts with an LI instruction that loads $v0 with an immediate 
number of the syscall required.  A SYSCALL instruction then immediately 
follows. In the latter case $v0 is arranged to have been preloaded and the 
piece starts with a SYSCALL instruction.

 That works if the syscall is executed the first time, because the 
compiler will have arranged for $v0 to contain the correct value.  It does 
not in the case of a syscall restart as the compiler-generated instruction 
immediately preceding SYSCALL may not necessarily be one to load $v0 with 
the value required.

 The failure mode is unlikely to trigger as the INTERNAL_SYSCALL_NCS 
wrapper is only used in a couple of places and then the offending syscall 
would have to be restarted as well.  The symptom would usually be an 
intermittent program failure and would be hard to debug.  The issue was 
noticed by code inspection while making changes in this area.

 Here is a change to address the problem.  It rearranges the wrappers such 
that there is always an instruction to reload $v0 before the SYSCALL 
instruction.  I have chosen $s0 as the place to preserve the syscall 
number per usual ABI conventions and consequently the MOVE instruction to 
move it into place.

 That required a further arrangement where the library is built as 
microMIPS code -- microMIPS MOVE is normally encoded by GAS as a short 
two-byte (16-bit) instruction.  That breaks the PC calculation done by the 
kernel as the restart would then happen either two instructions before 
SYSCALL (if the second previous instruction was 16-bit too) or, worse yet, 
in the middle of the second previous instruction (if that happened to be a 
32-bit instruction).  In the microMIPS mode the MOVE instruction is 
forcefully encoded into its 32-bit form with the use of an instruction 
size override suffix.  This is what the MOVE32 macro is about.

 The change was regression-tested successfully for the following 
configurations (compiler flag/multilib options), for both endiannesses 
each (the -EB and -EL compiler option, respectively):

* standard MIPS ISA, o32 (-mabi=32),

* standard MIPS ISA, n64 (-mabi=64),

* standard MIPS ISA, n32 (-mabi=n32),

* standard MIPS ISA, o32, soft-float (-mabi=32 -msoft-float),

* standard MIPS ISA, n64, soft-float (-mabi=64 -msoft-float),

* standard MIPS ISA, n32, soft-float (-mabi=n32 -msoft-float),

* microMIPS ISA, o32 (-mmicromips -mabi=32),

* microMIPS ISA, o32, soft-float (-mmicromips -mabi=32 -msoft-float),

with the MIPS32r2 or MIPS64r2 ISA level selected as applicable.

 Please apply.

2013-01-23  Maciej W. Rozycki  <macro@codesourcery.com>

	[BZ #15054]
	* sysdeps/unix/sysv/linux/mips/mips32/sysdep.h (MOVE32):
	New macro.
	(INTERNAL_SYSCALL_NCS): Use it.  Rewrite to respect the syscall
	restart convention.
	(INTERNAL_SYSCALL): Rewrite to respect the syscall restart
	convention.
	(internal_syscall0, internal_syscall1): Likewise.
	(internal_syscall2, internal_syscall3): Likewise.
	(internal_syscall4, internal_syscall5): Likewise.
	(internal_syscall6, internal_syscall7): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h (MOVE32):
	New macro.
	(INTERNAL_SYSCALL_NCS): Use it.  Rewrite to respect the syscall
	restart convention.
	(INTERNAL_SYSCALL): Rewrite to respect the syscall restart
	convention.
	(internal_syscall0, internal_syscall1): Likewise.
	(internal_syscall2, internal_syscall3): Likewise.
	(internal_syscall4, internal_syscall5): Likewise.
	(internal_syscall6): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h (MOVE32):
	New macro.
	(INTERNAL_SYSCALL_NCS): Use it.  Rewrite to respect the syscall
	restart convention.
	(INTERNAL_SYSCALL): Rewrite to respect the syscall restart
	convention.
	(internal_syscall0, internal_syscall1): Likewise.
	(internal_syscall2, internal_syscall3): Likewise.
	(internal_syscall4, internal_syscall5): Likewise.
	(internal_syscall6): Likewise.

  Maciej

glibc-mips-syscall-restart.diff
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h	2013-01-17 00:52:34.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h	2013-01-17 01:12:40.907765959 +0000
@@ -67,25 +67,45 @@
 #undef INTERNAL_SYSCALL_ERRNO
 #define INTERNAL_SYSCALL_ERRNO(val, err)     ((void) (err), val)
 
+/* Note that the Linux syscall restart convention requires the instruction
+   immediately preceding SYSCALL to initialize $v0 with the syscall number.
+   Then if a restart triggers, $v0 will have been clobbered by the syscall
+   interrupted, and needs to be reinititalized.  The kernel will decrement
+   the PC by 4 before switching back to the user mode so that $v0 has been
+   reloaded before SYSCALL is executed again.  This implies the place $v0
+   is loaded from must be preserved across a syscall, e.g. an immediate,
+   static register, stack slot, etc.  This also means we have to force a
+   32-bit encoding of the microMIPS MOVE instruction if one is used.  */
+
+#ifdef __mips_micromips
+#define MOVE32 "move32"
+#else
+#define MOVE32 "move"
+#endif
+
 #undef INTERNAL_SYSCALL
-#define INTERNAL_SYSCALL(name, err, nr, args...) \
-	internal_syscall##nr (, "li\t$2, %2\t\t\t# " #name "\n\t",	\
-			      "i" (SYS_ify (name)), err, args)
+#define INTERNAL_SYSCALL(name, err, nr, args...)			\
+	internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t",	\
+			      "IK" (SYS_ify (name)),			\
+			      0, err, args)
 
 #undef INTERNAL_SYSCALL_NCS
-#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
-	internal_syscall##nr (= number, , "r" (__v0), err, args)
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)			\
+	internal_syscall##nr (MOVE32 "\t%0, %2\n\t",			\
+			      "r" (__s0),				\
+			      number, err, args)
 
-#define internal_syscall0(ncs_init, cs_init, input, err, dummy...)	\
+#define internal_syscall0(v0_init, input, number, err, dummy...)	\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a3 asm("$7");					\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set reorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
@@ -97,17 +117,18 @@
 	_sys_result;							\
 })
 
-#define internal_syscall1(ncs_init, cs_init, input, err, arg1)		\
+#define internal_syscall1(v0_init, input, number, err, arg1)		\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a3 asm("$7");					\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set reorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
@@ -119,20 +140,21 @@
 	_sys_result;							\
 })
 
-#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2)	\
+#define internal_syscall2(v0_init, input, number, err, arg1, arg2)	\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a3 asm("$7");					\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
-	".set\treorder"						\
+	".set\treorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
 	: input, "r" (__a0), "r" (__a1)					\
 	: __SYSCALL_CLOBBERS);						\
@@ -142,21 +164,23 @@
 	_sys_result;							\
 })
 
-#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3)\
+#define internal_syscall3(v0_init, input, number, err,			\
+			  arg1, arg2, arg3)				\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a2 asm("$6") = (long) (arg3);			\
 	register long __a3 asm("$7");					\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
-	".set\treorder"						\
+	".set\treorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
 	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\
 	: __SYSCALL_CLOBBERS);						\
@@ -166,21 +190,23 @@
 	_sys_result;							\
 })
 
-#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4)\
+#define internal_syscall4(v0_init, input, number, err,			\
+			  arg1, arg2, arg3, arg4)			\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a2 asm("$6") = (long) (arg3);			\
 	register long __a3 asm("$7") = (long) (arg4);			\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
-	".set\treorder"						\
+	".set\treorder"							\
 	: "=r" (__v0), "+r" (__a3)					\
 	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\
 	: __SYSCALL_CLOBBERS);						\
@@ -197,13 +223,15 @@
 #define FORCE_FRAME_POINTER						\
   void *volatile __fp_force __attribute__ ((unused)) = alloca (4)
 
-#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5)\
+#define internal_syscall5(v0_init, input, number, err,			\
+			  arg1, arg2, arg3, arg4, arg5)			\
 ({									\
 	long _sys_result;						\
 									\
 	FORCE_FRAME_POINTER;						\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a2 asm("$6") = (long) (arg3);			\
@@ -212,10 +240,10 @@
 	".set\tnoreorder\n\t"						\
 	"subu\t$29, 32\n\t"						\
 	"sw\t%6, 16($29)\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	"addiu\t$29, 32\n\t"						\
-	".set\treorder"						\
+	".set\treorder"							\
 	: "=r" (__v0), "+r" (__a3)					\
 	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\
 	  "r" ((long) (arg5))						\
@@ -226,13 +254,15 @@
 	_sys_result;							\
 })
 
-#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6)\
+#define internal_syscall6(v0_init, input, number, err,			\
+			  arg1, arg2, arg3, arg4, arg5, arg6)		\
 ({									\
 	long _sys_result;						\
 									\
 	FORCE_FRAME_POINTER;						\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a2 asm("$6") = (long) (arg3);			\
@@ -242,10 +272,10 @@
 	"subu\t$29, 32\n\t"						\
 	"sw\t%6, 16($29)\n\t"						\
 	"sw\t%7, 20($29)\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	"addiu\t$29, 32\n\t"						\
-	".set\treorder"						\
+	".set\treorder"							\
 	: "=r" (__v0), "+r" (__a3)					\
 	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\
 	  "r" ((long) (arg5)), "r" ((long) (arg6))			\
@@ -256,13 +286,15 @@
 	_sys_result;							\
 })
 
-#define internal_syscall7(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\
+#define internal_syscall7(v0_init, input, number, err,			\
+			  arg1, arg2, arg3, arg4, arg5, arg6, arg7)	\
 ({									\
 	long _sys_result;						\
 									\
 	FORCE_FRAME_POINTER;						\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a2 asm("$6") = (long) (arg3);			\
@@ -273,10 +305,10 @@
 	"sw\t%6, 16($29)\n\t"						\
 	"sw\t%7, 20($29)\n\t"						\
 	"sw\t%8, 24($29)\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	"addiu\t$29, 32\n\t"						\
-	".set\treorder"						\
+	".set\treorder"							\
 	: "=r" (__v0), "+r" (__a3)					\
 	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\
 	  "r" ((long) (arg5)), "r" ((long) (arg6)), "r" ((long) (arg7))	\
Index: ports/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h	2013-01-17 00:52:34.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips64/n32/sysdep.h	2013-01-17 01:12:40.907765959 +0000
@@ -71,25 +71,45 @@
 #undef INTERNAL_SYSCALL_ERRNO
 #define INTERNAL_SYSCALL_ERRNO(val, err)     ((void) (err), val)
 
+/* Note that the Linux syscall restart convention requires the instruction
+   immediately preceding SYSCALL to initialize $v0 with the syscall number.
+   Then if a restart triggers, $v0 will have been clobbered by the syscall
+   interrupted, and needs to be reinititalized.  The kernel will decrement
+   the PC by 4 before switching back to the user mode so that $v0 has been
+   reloaded before SYSCALL is executed again.  This implies the place $v0
+   is loaded from must be preserved across a syscall, e.g. an immediate,
+   static register, stack slot, etc.  This also means we have to force a
+   32-bit encoding of the microMIPS MOVE instruction if one is used.  */
+
+#ifdef __mips_micromips
+#define MOVE32 "move32"
+#else
+#define MOVE32 "move"
+#endif
+
 #undef INTERNAL_SYSCALL
-#define INTERNAL_SYSCALL(name, err, nr, args...) \
-	internal_syscall##nr (, "li\t$2, %2\t\t\t# " #name "\n\t",	\
-			      "i" (SYS_ify (name)), err, args)
+#define INTERNAL_SYSCALL(name, err, nr, args...)			\
+	internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t",	\
+			      "IK" (SYS_ify (name)),			\
+			      0, err, args)
 
 #undef INTERNAL_SYSCALL_NCS
-#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
-	internal_syscall##nr (= number, , "r" (__v0), err, args)
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)			\
+	internal_syscall##nr (MOVE32 "\t%0, %2\n\t",			\
+			      "r" (__s0),				\
+			      number, err, args)
 
-#define internal_syscall0(ncs_init, cs_init, input, err, dummy...)	\
+#define internal_syscall0(v0_init, input, number, err, dummy...)	\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long long __v0 asm("$2") ncs_init;			\
+	register long long __s0 asm("$16") __attribute__((unused)) = number; \
+	register long long __v0 asm("$2");				\
 	register long long __a3 asm("$7");				\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set reorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
@@ -101,17 +121,18 @@
 	_sys_result;							\
 })
 
-#define internal_syscall1(ncs_init, cs_init, input, err, arg1)		\
+#define internal_syscall1(v0_init, input, number, err, arg1)		\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long long __v0 asm("$2") ncs_init;			\
+	register long long __s0 asm("$16") __attribute__((unused)) = number; \
+	register long long __v0 asm("$2");				\
 	register long long __a0 asm("$4") = ARGIFY (arg1);		\
 	register long long __a3 asm("$7");				\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set reorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
@@ -123,18 +144,19 @@
 	_sys_result;							\
 })
 
-#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2)	\
+#define internal_syscall2(v0_init, input, number, err, arg1, arg2)	\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long long __v0 asm("$2") ncs_init;			\
+	register long long __s0 asm("$16") __attribute__((unused)) = number; \
+	register long long __v0 asm("$2");				\
 	register long long __a0 asm("$4") = ARGIFY (arg1);		\
 	register long long __a1 asm("$5") = ARGIFY (arg2);		\
 	register long long __a3 asm("$7");				\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set\treorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
@@ -146,19 +168,21 @@
 	_sys_result;							\
 })
 
-#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3) \
+#define internal_syscall3(v0_init, input, number, err,			\
+			  arg1, arg2, arg3)				\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long long __v0 asm("$2") ncs_init;			\
+	register long long __s0 asm("$16") __attribute__((unused)) = number; \
+	register long long __v0 asm("$2");				\
 	register long long __a0 asm("$4") = ARGIFY (arg1);		\
 	register long long __a1 asm("$5") = ARGIFY (arg2);		\
 	register long long __a2 asm("$6") = ARGIFY (arg3);		\
 	register long long __a3 asm("$7");				\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set\treorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
@@ -170,19 +194,21 @@
 	_sys_result;							\
 })
 
-#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4) \
+#define internal_syscall4(v0_init, input, number, err,			\
+			  arg1, arg2, arg3, arg4)			\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long long __v0 asm("$2") ncs_init;			\
+	register long long __s0 asm("$16") __attribute__((unused)) = number; \
+	register long long __v0 asm("$2");				\
 	register long long __a0 asm("$4") = ARGIFY (arg1);		\
 	register long long __a1 asm("$5") = ARGIFY (arg2);		\
 	register long long __a2 asm("$6") = ARGIFY (arg3);		\
 	register long long __a3 asm("$7") = ARGIFY (arg4);		\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set\treorder"							\
 	: "=r" (__v0), "+r" (__a3)					\
@@ -194,12 +220,14 @@
 	_sys_result;							\
 })
 
-#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5) \
+#define internal_syscall5(v0_init, input, number, err,			\
+			  arg1, arg2, arg3, arg4, arg5)			\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long long __v0 asm("$2") ncs_init;			\
+	register long long __s0 asm("$16") __attribute__((unused)) = number; \
+	register long long __v0 asm("$2");				\
 	register long long __a0 asm("$4") = ARGIFY (arg1);		\
 	register long long __a1 asm("$5") = ARGIFY (arg2);		\
 	register long long __a2 asm("$6") = ARGIFY (arg3);		\
@@ -207,7 +235,7 @@
 	register long long __a4 asm("$8") = ARGIFY (arg5);		\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set\treorder"							\
 	: "=r" (__v0), "+r" (__a3)					\
@@ -219,12 +247,14 @@
 	_sys_result;							\
 })
 
-#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6) \
+#define internal_syscall6(v0_init, input, number, err,			\
+			  arg1, arg2, arg3, arg4, arg5, arg6)		\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long long __v0 asm("$2") ncs_init;			\
+	register long long __s0 asm("$16") __attribute__((unused)) = number; \
+	register long long __v0 asm("$2");				\
 	register long long __a0 asm("$4") = ARGIFY (arg1);		\
 	register long long __a1 asm("$5") = ARGIFY (arg2);		\
 	register long long __a2 asm("$6") = ARGIFY (arg3);		\
@@ -233,7 +263,7 @@
 	register long long __a5 asm("$9") = ARGIFY (arg6);		\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set\treorder"							\
 	: "=r" (__v0), "+r" (__a3)					\
Index: ports/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h	2013-01-17 00:52:34.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips64/n64/sysdep.h	2013-01-17 01:12:40.907765959 +0000
@@ -67,25 +67,45 @@
 #undef INTERNAL_SYSCALL_ERRNO
 #define INTERNAL_SYSCALL_ERRNO(val, err)     ((void) (err), val)
 
+/* Note that the Linux syscall restart convention requires the instruction
+   immediately preceding SYSCALL to initialize $v0 with the syscall number.
+   Then if a restart triggers, $v0 will have been clobbered by the syscall
+   interrupted, and needs to be reinititalized.  The kernel will decrement
+   the PC by 4 before switching back to the user mode so that $v0 has been
+   reloaded before SYSCALL is executed again.  This implies the place $v0
+   is loaded from must be preserved across a syscall, e.g. an immediate,
+   static register, stack slot, etc.  This also means we have to force a
+   32-bit encoding of the microMIPS MOVE instruction if one is used.  */
+
+#ifdef __mips_micromips
+#define MOVE32 "move32"
+#else
+#define MOVE32 "move"
+#endif
+
 #undef INTERNAL_SYSCALL
-#define INTERNAL_SYSCALL(name, err, nr, args...) \
-	internal_syscall##nr (, "li\t$2, %2\t\t\t# " #name "\n\t",	\
-			      "i" (SYS_ify (name)), err, args)
+#define INTERNAL_SYSCALL(name, err, nr, args...)			\
+	internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t",	\
+			      "IK" (SYS_ify (name)),			\
+			      0, err, args)
 
 #undef INTERNAL_SYSCALL_NCS
-#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
-	internal_syscall##nr (= number, , "r" (__v0), err, args)
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)			\
+	internal_syscall##nr (MOVE32 "\t%0, %2\n\t",			\
+			      "r" (__s0),				\
+			      number, err, args)
 
-#define internal_syscall0(ncs_init, cs_init, input, err, dummy...)	\
+#define internal_syscall0(v0_init, input, number, err, dummy...)	\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a3 asm("$7");					\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set reorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
@@ -97,17 +117,18 @@
 	_sys_result;							\
 })
 
-#define internal_syscall1(ncs_init, cs_init, input, err, arg1)		\
+#define internal_syscall1(v0_init, input, number, err, arg1)		\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a3 asm("$7");					\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set reorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
@@ -119,18 +140,19 @@
 	_sys_result;							\
 })
 
-#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2)	\
+#define internal_syscall2(v0_init, input, number, err, arg1, arg2)	\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a3 asm("$7");					\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set\treorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
@@ -142,19 +164,21 @@
 	_sys_result;							\
 })
 
-#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3) \
+#define internal_syscall3(v0_init, input, number, err,			\
+			  arg1, arg2, arg3)				\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a2 asm("$6") = (long) (arg3);			\
 	register long __a3 asm("$7");					\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set\treorder"							\
 	: "=r" (__v0), "=r" (__a3)					\
@@ -166,19 +190,21 @@
 	_sys_result;							\
 })
 
-#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4) \
+#define internal_syscall4(v0_init, input, number, err,			\
+			  arg1, arg2, arg3, arg4)			\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a2 asm("$6") = (long) (arg3);			\
 	register long __a3 asm("$7") = (long) (arg4);			\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set\treorder"							\
 	: "=r" (__v0), "+r" (__a3)					\
@@ -190,12 +216,14 @@
 	_sys_result;							\
 })
 
-#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5) \
+#define internal_syscall5(v0_init, input, number, err,			\
+			  arg1, arg2, arg3, arg4, arg5)			\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a2 asm("$6") = (long) (arg3);			\
@@ -203,7 +231,7 @@
 	register long __a4 asm("$8") = (long) (arg5);			\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set\treorder"							\
 	: "=r" (__v0), "+r" (__a3)					\
@@ -215,12 +243,14 @@
 	_sys_result;							\
 })
 
-#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6) \
+#define internal_syscall6(v0_init, input, number, err,			\
+			  arg1, arg2, arg3, arg4, arg5, arg6)		\
 ({									\
 	long _sys_result;						\
 									\
 	{								\
-	register long __v0 asm("$2") ncs_init;				\
+	register long __s0 asm("$16") __attribute__((unused)) = number;	\
+	register long __v0 asm("$2");					\
 	register long __a0 asm("$4") = (long) (arg1);			\
 	register long __a1 asm("$5") = (long) (arg2);			\
 	register long __a2 asm("$6") = (long) (arg3);			\
@@ -229,7 +259,7 @@
 	register long __a5 asm("$9") = (long) (arg6);			\
 	__asm__ volatile (						\
 	".set\tnoreorder\n\t"						\
-	cs_init								\
+	v0_init								\
 	"syscall\n\t"							\
 	".set\treorder"							\
 	: "=r" (__v0), "+r" (__a3)					\


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]