| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 | /* * 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> */#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)*/intclone (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.	 */	/* 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)		);        /* Sanity check the arguments */        err = -EINVAL;        if (!fn)                goto syscall_error;        if (!child_stack)                goto syscall_error;	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;	}	/* NB: from here you exclusively in child thread */	/* 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));syscall_error:        __set_errno (-err);        return -1;}
 |