clone.c 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /*
  2. * clone syscall for OpenRISC
  3. *
  4. * Copyright (c) 2010 Jonas Bonn <jonas@southpole.se>
  5. * Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au>
  6. * Copyright (C) 2002,03 NEC Electronics Corporation
  7. * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
  8. *
  9. * This file is subject to the terms and conditions of the GNU Lesser
  10. * General Public License. See the file COPYING.LIB in the main
  11. * directory of this archive for more details.
  12. *
  13. * OpenRISC port by Jonas Bonn <jonas@southpole.se>
  14. */
  15. #include <errno.h>
  16. #include <sys/syscall.h>
  17. #include <sched.h>
  18. #include <unistd.h>
  19. /* The userland implementation is:
  20. int clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg, ...)
  21. the kernel entry is:
  22. int clone (long flags, void *child_stack)
  23. */
  24. int
  25. clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg, ...)
  26. {
  27. int err;
  28. /* OK, here's the skinny on this one...
  29. * OR1K GCC does weird things with varargs functions... the last
  30. * parameter is NEVER passed on the stack -- i.e. arg, in this case.
  31. * So we need to push at least 'arg' onto the child stack so that
  32. * the new thread can find it. Just to be totally safe, we'll
  33. * push both 'fn' and 'arg'; that way we don't need to care what
  34. * GCC does with parameters, whether they are passed in registers
  35. * or on stack.
  36. */
  37. /* Put 'fn' and 'arg' on child stack */
  38. __asm__ __volatile__ (
  39. "l.sw -4(%0),%1;"
  40. "l.sw -8(%0),%2;"
  41. :
  42. : "r" (child_stack), "r" (fn), "r" (arg)
  43. );
  44. /* Sanity check the arguments */
  45. err = -EINVAL;
  46. if (!fn)
  47. goto syscall_error;
  48. if (!child_stack)
  49. goto syscall_error;
  50. err = INLINE_SYSCALL(clone, 2, flags, child_stack);
  51. /* NB: from here you are in child thread or parent thread.
  52. *
  53. * Do not use any functions here that may write data _up_
  54. * onto the stack because they will overwrite the child's
  55. * thread descriptor... i.e. don't use printf
  56. */
  57. if (err < 0)
  58. goto syscall_error;
  59. else if (err != 0) {
  60. return err;
  61. }
  62. /* NB: from here you exclusively in child thread */
  63. /* Grab 'fn' and 'arg' from child stack */
  64. __asm__ __volatile__ (
  65. "l.lwz %0,-4(%2);"
  66. "l.lwz %1,-8(%2);"
  67. : "=&r" (fn), "=r" (arg)
  68. : "r" (child_stack)
  69. : "0", "1"
  70. );
  71. _exit(fn(arg));
  72. syscall_error:
  73. __set_errno (-err);
  74. return -1;
  75. }