From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31825 invoked by alias); 23 Jan 2013 03:09:28 -0000 Received: (qmail 31809 invoked by uid 22791); 23 Jan 2013 03:09:27 -0000 X-SWARE-Spam-Status: No, hits=-3.7 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 23 Jan 2013 03:09:16 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1TxqiB-0001YR-IZ from Maciej_Rozycki@mentor.com for libc-ports@sourceware.org; Tue, 22 Jan 2013 19:09:15 -0800 Received: from SVR-IES-FEM-03.mgc.mentorg.com ([137.202.0.108]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Tue, 22 Jan 2013 19:09:15 -0800 Received: from [172.30.4.21] (137.202.0.76) by SVR-IES-FEM-03.mgc.mentorg.com (137.202.0.108) with Microsoft SMTP Server id 14.1.289.1; Wed, 23 Jan 2013 03:09:12 +0000 Date: Wed, 23 Jan 2013 03:09:00 -0000 From: "Maciej W. Rozycki" To: Subject: [PATCH][BZ #15054] MIPS: Fix syscall wrappers for syscall restart support Message-ID: User-Agent: Alpine 1.10 (DEB 962 2008-03-14) MIME-Version: 1.0 Content-Type: text/plain; charset="US-ASCII" Mailing-List: contact libc-ports-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: libc-ports-owner@sourceware.org X-SW-Source: 2013-01/txt/msg00035.txt.bz2 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 [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) \