aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/unix
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix')
-rw-r--r--sysdeps/unix/sysv/linux/kernel-features.h4
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h61
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S56
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/syscall.S1
4 files changed, 78 insertions, 44 deletions
diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h
index 6b1bdf2517..3159dd1ada 100644
--- a/sysdeps/unix/sysv/linux/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/kernel-features.h
@@ -196,9 +196,11 @@
# define __ASSUME_AT_XID 1
#endif
-/* Starting with 2.4.5 kernels PPC passes the AUXV in the standard way. */
+/* Starting with 2.4.5 kernels PPC passes the AUXV in the standard way
+ and the vfork syscall made it into the official kernel. */
#if __LINUX_KERNEL_VERSION >= (132096+5) && defined __powerpc__
# define __ASSUME_STD_AUXV 1
+# define __ASSUME_VFORK_SYSCALL 1
#endif
/* Starting with 2.4.5 kernels the mmap2 syscall made it into the official
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
index e2d599c22b..b31c3db653 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
@@ -54,53 +54,29 @@
# include <errno.h>
-/* On powerpc a system call basically clobbers the same registers like a
- function call, with the exception of LR (which is needed for the
- "sc; bnslr" sequence) and CR (where only CR0.SO is clobbered to signal
- an error return status). */
-
# undef INLINE_SYSCALL
# define INLINE_SYSCALL(name, nr, args...) \
({ \
- register long r0 __asm__ ("r0"); \
- register long r3 __asm__ ("r3"); \
- register long r4 __asm__ ("r4"); \
- register long r5 __asm__ ("r5"); \
- register long r6 __asm__ ("r6"); \
- register long r7 __asm__ ("r7"); \
- register long r8 __asm__ ("r8"); \
- register long r9 __asm__ ("r9"); \
- register long r10 __asm__ ("r10"); \
- register long r11 __asm__ ("r11"); \
- register long r12 __asm__ ("r12"); \
- long ret, err; \
- LOADARGS_##nr(name, args); \
- __asm__ __volatile__ \
- ("sc\n\t" \
- "mfcr %0" \
- : "=&r" (r0), \
- "=&r" (r3), "=&r" (r4), "=&r" (r5), "=&r" (r6), "=&r" (r7), \
- "=&r" (r8), "=&r" (r9), "=&r" (r10), "=&r" (r11), "=&r" (r12) \
- : ASM_INPUT_##nr \
- : "cr0", "ctr", "memory"); \
- err = r0; \
- ret = r3; \
- if (__builtin_expect (err & (1 << 28), 0)) \
+ INTERNAL_SYSCALL_DECL (sc_err); \
+ long sc_ret = INTERNAL_SYSCALL (name, sc_err, nr, args); \
+ if (INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \
{ \
- __set_errno (ret); \
- ret = -1L; \
+ __set_errno (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err)); \
+ sc_ret = -1L; \
} \
- ret; \
+ sc_ret; \
})
/* Define a macro which expands inline into the wrapper code for a system
call. This use is for internal calls that do not need to handle errors
- normally. It will never touch errno. This returns just what the kernel
- gave back in the non-error (CR0.SO cleared) case, otherwise (CR0.SO set)
- the negation of the return value in the kernel gets reverted. */
+ normally. It will never touch errno.
+ On powerpc a system call basically clobbers the same registers like a
+ function call, with the exception of LR (which is needed for the
+ "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) do { } while (0)
+# define INTERNAL_SYSCALL_DECL(err) long err
# undef INTERNAL_SYSCALL
# define INTERNAL_SYSCALL(name, err, nr, args...) \
@@ -118,24 +94,23 @@
register long r12 __asm__ ("r12"); \
LOADARGS_##nr(name, args); \
__asm__ __volatile__ \
- ("sc\n\t" \
- "bns+ 0f\n\t" \
- "neg %1,%1\n" \
- "0:" \
+ ("sc \n\t" \
+ "mfcr %0" \
: "=&r" (r0), \
"=&r" (r3), "=&r" (r4), "=&r" (r5), "=&r" (r6), "=&r" (r7), \
"=&r" (r8), "=&r" (r9), "=&r" (r10), "=&r" (r11), "=&r" (r12) \
: ASM_INPUT_##nr \
: "cr0", "ctr", "memory"); \
+ err = r0; \
(int) r3; \
})
# undef INTERNAL_SYSCALL_ERROR_P
# define INTERNAL_SYSCALL_ERROR_P(val, err) \
- ((unsigned long) (val) >= 0xfffff001u)
+ (__builtin_expect (err & (1 << 28), 0))
# undef INTERNAL_SYSCALL_ERRNO
-# define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
+# define INTERNAL_SYSCALL_ERRNO(val, err) (val)
# define LOADARGS_0(name, dummy) \
r0 = __NR_##name
@@ -181,4 +156,4 @@
#endif /* __ASSEMBLER__ */
-#endif /* linux/powerpc/sysdep.h */
+#endif /* linux/powerpc/powerpc32/sysdep.h */
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S
new file mode 100644
index 0000000000..9a0f53e99e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S
@@ -0,0 +1,56 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+#define _ERRNO_H 1
+#include <bits/errno.h>
+#include <kernel-features.h>
+
+/* Clone the calling process, but without copying the whole address space.
+ The calling process is suspended until the new process exits or is
+ replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
+ and the process ID of the new process to the old process. */
+
+ENTRY (__vfork)
+
+#ifdef __NR_vfork
+
+ DO_CALL (SYS_ify (vfork))
+
+# ifdef __ASSUME_VFORK_SYSCALL
+ PSEUDO_RET
+# else
+ bnslr+
+ /* Check if vfork syscall is known at all. */
+ cmpwi r3,ENOSYS
+ bne JUMPTARGET(__syscall_error)
+
+# endif
+#endif
+
+#ifndef __ASSUME_VFORK_SYSCALL
+ /* If we don't have vfork, fork is close enough. */
+
+ DO_CALL (SYS_ify (fork))
+ PSEUDO_RET
+#endif
+
+PSEUDO_END (__vfork)
+libc_hidden_def (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall.S b/sysdeps/unix/sysv/linux/powerpc/syscall.S
index aaff02d78a..aab3c53004 100644
--- a/sysdeps/unix/sysv/linux/powerpc/syscall.S
+++ b/sysdeps/unix/sysv/linux/powerpc/syscall.S
@@ -25,6 +25,7 @@ ENTRY (syscall)
mr r5,r6
mr r6,r7
mr r7,r8
+ mr r8,r9
sc
PSEUDO_RET
PSEUDO_END (syscall)