From 4d8e5484afb4978f672a8568ddd12e628fb02724 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 8 Oct 2015 20:28:39 +0200 Subject: add new architecture support for or1k Information about Openrisc: http://opencores.org/or1k/Main_Page Integrated from: https://github.com/openrisc/uClibc-or1k --- libc/sysdeps/linux/or1k/clone.c | 88 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 libc/sysdeps/linux/or1k/clone.c (limited to 'libc/sysdeps/linux/or1k/clone.c') diff --git a/libc/sysdeps/linux/or1k/clone.c b/libc/sysdeps/linux/or1k/clone.c new file mode 100644 index 000000000..ebb048ad4 --- /dev/null +++ b/libc/sysdeps/linux/or1k/clone.c @@ -0,0 +1,88 @@ +/* + * clone syscall for OpenRISC + * + * Copyright (c) 2010 Jonas Bonn + * Copyright (C) 2003 John Williams + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader + * + * 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 + */ + +#include +#include +#include +#include + +/* 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. + */ + + /* 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; +} -- cgit v1.2.3