This is the mail archive of the
libc-ports@sources.redhat.com
mailing list for the libc-ports project.
[PATCH][BZ #15054] MIPS: Fix syscall wrappers for syscall restart support
- From: "Maciej W. Rozycki" <macro at codesourcery dot com>
- To: <libc-ports at sourceware dot org>
- Date: Wed, 23 Jan 2013 03:09:03 +0000
- Subject: [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) \