summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/or1k/clone.c
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2017-04-17 14:48:50 +0200
committerWaldemar Brodkorb <wbx@openadk.org>2017-05-14 10:29:09 +0200
commit69ea4c1f65bff99575cd7f0210312dc355929240 (patch)
tree43fe11a4e27c85b742e2434f6e8ec0b25576d8af /libc/sysdeps/linux/or1k/clone.c
parentbe6a02b9a0317a7441de9aa2e3e07fe838787d57 (diff)
or1k: add clone() from old GNU libc implementation
Diffstat (limited to 'libc/sysdeps/linux/or1k/clone.c')
-rw-r--r--libc/sysdeps/linux/or1k/clone.c127
1 files changed, 49 insertions, 78 deletions
diff --git a/libc/sysdeps/linux/or1k/clone.c b/libc/sysdeps/linux/or1k/clone.c
index ebb048ad4..2b61b638f 100644
--- a/libc/sysdeps/linux/or1k/clone.c
+++ b/libc/sysdeps/linux/or1k/clone.c
@@ -1,88 +1,59 @@
-/*
- * clone syscall for OpenRISC
- *
- * Copyright (c) 2010 Jonas Bonn <jonas@southpole.se>
- * Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au>
- * Copyright (C) 2002,03 NEC Electronics Corporation
- * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
- *
- * This file is subject to the terms and conditions of the GNU Lesser
- * General Public License. See the file COPYING.LIB in the main
- * directory of this archive for more details.
- *
- * OpenRISC port by Jonas Bonn <jonas@southpole.se>
- */
+/* Copyright (C) 1998, 2002, 2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
-#include <errno.h>
-#include <sys/syscall.h>
-#include <sched.h>
-#include <unistd.h>
-
-/* The userland implementation is:
- int clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg, ...)
- the kernel entry is:
- int clone (long flags, void *child_stack)
-*/
-
-int
-clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg, ...)
-{
- int err;
-
- /* OK, here's the skinny on this one...
- * OR1K GCC does weird things with varargs functions... the last
- * parameter is NEVER passed on the stack -- i.e. arg, in this case.
- * So we need to push at least 'arg' onto the child stack so that
- * the new thread can find it. Just to be totally safe, we'll
- * push both 'fn' and 'arg'; that way we don't need to care what
- * GCC does with parameters, whether they are passed in registers
- * or on stack.
- */
+ 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.
- /* Put 'fn' and 'arg' on child stack */
- __asm__ __volatile__ (
- "l.sw -4(%0),%1;"
- "l.sw -8(%0),%2;"
- :
- : "r" (child_stack), "r" (fn), "r" (arg)
- );
+ 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.
- /* Sanity check the arguments */
- err = -EINVAL;
- if (!fn)
- goto syscall_error;
- if (!child_stack)
- goto syscall_error;
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
- err = INLINE_SYSCALL(clone, 2, flags, child_stack);
-
- /* NB: from here you are in child thread or parent thread.
- *
- * Do not use any functions here that may write data _up_
- * onto the stack because they will overwrite the child's
- * thread descriptor... i.e. don't use printf
- */
-
- if (err < 0)
- goto syscall_error;
- else if (err != 0) {
- return err;
- }
+#include <stdarg.h>
+#include <sysdep.h>
+#include <unistd.h>
- /* NB: from here you exclusively in child thread */
+extern int __or1k_clone (int (*fn)(void *), void *child_stack,
+ int flags, void *arg, pid_t *ptid,
+ void *tls, pid_t *ctid);
- /* Grab 'fn' and 'arg' from child stack */
- __asm__ __volatile__ (
- "l.lwz %0,-4(%2);"
- "l.lwz %1,-8(%2);"
- : "=&r" (fn), "=r" (arg)
- : "r" (child_stack)
- : "0", "1"
- );
- _exit(fn(arg));
+/* or1k ABI uses stack for varargs, syscall uses registers.
+ * This function moves from varargs to regs. */
+int
+__clone (int (*fn)(void *), void *child_stack,
+ int flags, void *arg, ...
+ /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ )
+{
+ void *ptid;
+ void *tls;
+ void *ctid;
+ va_list ap;
+ int err;
+
+ va_start (ap, arg);
+ ptid = va_arg (ap, void *);
+ tls = va_arg (ap, void *);
+ ctid = va_arg (ap, void *);
+ va_end (ap);
+
+ /* Sanity check the arguments */
+ err = -EINVAL;
+ if (!fn)
+ goto syscall_error;
+ if (!child_stack)
+ goto syscall_error;
+
+ return __or1k_clone (fn, child_stack, flags, arg, ptid, tls, ctid);
syscall_error:
- __set_errno (-err);
- return -1;
+ __set_errno (-err);
+ return -1;
}
+weak_alias (__clone, clone)