Просмотр исходного кода

powerpc: return -errno from INTERNAL_SYSCALL

powerpc reported syscall errors the way its pre-Linux ABI did: the error
code positive in r3, the indication in cr0.SO, handed to the caller
through the err out-parameter.  Everything that reads an INTERNAL_SYSCALL
result the way the other architectures produce it -- negative on error --
was therefore wrong here:

  sem_wait.c, sem_timedwait.c   "err != 0 && err != -EWOULDBLOCK" never
                                recognised the retry case, so a futex
                                wait that raced turned into a failure
                                with errno = -11 / -110
  sem_post.c (both copies)      "err < 0" was never true, so an error
                                from FUTEX_WAKE was silently dropped
  lowlevellock.c                lll_timedwait_tid() compares against
                                -ETIMEDOUT and never saw its timeout

Fold the flag into the return value where it is produced, as glibc does
in SYSCALL_SC since 2.32, and drop the INTERNAL_SYSCALL_DECL,
INTERNAL_SYSCALL_ERROR_P and INTERNAL_SYSCALL_ERRNO overrides so that the
generic definitions in bits/syscalls-common.h apply.

Nothing is lost in the conversion: the kernel derives the flag from the
very same negative range it hides.  arch/powerpc/kernel/interrupt.c:

	if (unlikely(r3 >= (unsigned long)-MAX_ERRNO) && is_not_scv) {
		...
			r3 = -r3;
			regs->ccr |= 0x10000000; /* Set SO bit in CR */

0x10000000 is bit 28, which is cr0.SO -- the CR holds eight four-bit
fields numbered from the most significant end, so cr0's fourth bit is bit
28 counted from the least significant one.  Masking rather than testing
for non-zero matters because mfcr reads the whole register, including
cr1..cr7.  The vDSO path reads the same bit, and its no-syscall fallback
signalled "no vDSO" by setting the flag by hand, which becomes -ENOSYS.

The is_not_scv above is worth a look: on POWER9 and later the kernel
returns through scv, which has no SO bit and returns -errno directly.
powerpc's own newer syscall ABI has left this convention behind.

The err parameter stays in the macro signatures, unused, exactly as on
arm; that keeps this change to one file.  alpha, ia64, mips, nios2 and
tile still carry the old convention and follow one at a time; the
parameter can go once they are converted.

Verified on powerpc/6.1.60 under qemu-system-ppc: 61 failures before, 57
after -- tst-sem5, tst-sem6 and their -O2 variants, without the futex
helper workaround.  The rest are the cancellation tests, a separate
problem.

Signed-off-by: Ramin Moussavi <lordrasmus@gmail.com>
ramin 1 неделя назад
Родитель
Сommit
b67a837b71
1 измененных файлов с 4 добавлено и 14 удалено
  1. 4 14
      libc/sysdeps/linux/powerpc/bits/syscalls.h

+ 4 - 14
libc/sysdeps/linux/powerpc/bits/syscalls.h

@@ -82,12 +82,10 @@
 
 # define INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK(name, err, nr, args...)	      \
   ({									      \
-    long int sc_ret = ENOSYS;						      \
+    long int sc_ret = -ENOSYS;						      \
 									      \
     if (__vdso_##name != NULL)						      \
       sc_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args);	      \
-    else								      \
-      err = 1 << 28;							      \
     sc_ret;								      \
   })
 
@@ -125,8 +123,7 @@
 	 "=&r" (r8), "=&r" (r9), "=&r" (r10), "=&r" (r11), "=&r" (r12)	      \
        : ASM_INPUT_##nr							      \
        : "cr0", "ctr", "lr", "memory");					      \
-    err = (long int) r0;						      \
-    (int) r3;								      \
+    ((long int) r0) & (1 << 28) ? -r3 : r3;				      \
   })
 
 /* Define a macro which expands inline into the wrapper code for a system
@@ -137,9 +134,6 @@
    "sc; bnslr+" sequence) and CR (where only CR0.SO is clobbered to signal
    an error return status).  */
 
-# undef INTERNAL_SYSCALL_DECL
-# define INTERNAL_SYSCALL_DECL(err) long int err __attribute__((unused))
-
 # define INTERNAL_SYSCALL_NCS(name, err, nr, args...)			\
 (__extension__ \
   ({									\
@@ -163,14 +157,10 @@
 	 "=&r" (r8), "=&r" (r9), "=&r" (r10), "=&r" (r11), "=&r" (r12)	\
        : ASM_INPUT_##nr							\
        : "cr0", "ctr", "memory");					\
-    err = r0;								\
-    (int) r3;								\
+    /* CR0.SO signals the error; fold it into a negative return value.  */ \
+    r0 & (1 << 28) ? -r3 : r3;						\
   }) \
 )
-# define INTERNAL_SYSCALL_ERROR_P(val, err) \
-  ((void) (val), unlikely ((err) & (1 << 28)))
-
-# define INTERNAL_SYSCALL_ERRNO(val, err)     (val)
 
 extern void __illegally_sized_syscall_arg1(void);
 extern void __illegally_sized_syscall_arg2(void);