clone.S 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
  3. *
  4. * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
  5. */
  6. #include <asm/errno.h>
  7. #include <sys/syscall.h>
  8. #include <sysdep.h>
  9. ; Per man, libc clone( ) is as follows
  10. ;
  11. ; int clone(int (*fn)(void *), void *child_stack,
  12. ; int flags, void *arg, ...
  13. ; /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */);
  14. ;
  15. ; NOTE: I'm assuming that the last 3 args are NOT var-args and in case all
  16. ; 3 are not relevant, caller will nevertheless pass those as NULL.
  17. ; Current (Jul 2012) upstream powerpc/clone.S assumes similarly.
  18. ; Our LTP (from 2007) doesn't seem to have tests to prove otherwise
  19. ; clone syscall in kernel (ABI: CONFIG_CLONE_BACKWARDS)
  20. ;
  21. ; int sys_clone(unsigned long clone_flags,
  22. ; unsigned long newsp,
  23. ; int __user *parent_tidptr,
  24. ; void *tls,
  25. ; int __user *child_tidptr)
  26. #define CLONE_SETTLS 0x00080000
  27. ENTRY(clone)
  28. cmp r0, 0 ; @fn can't be NULL
  29. cmp.ne r1, 0 ; @child_stack can't be NULL
  30. bz .L__sys_err
  31. ; save some of the orig args
  32. ; r0 containg @fn will be clobbered AFTER syscall (with ret val)
  33. ; rest are clobbered BEFORE syscall due to different arg ordering
  34. mov r10, r0 ; @fn
  35. mov r11, r3 ; @args
  36. mov r12, r2 ; @clone_flags
  37. mov r9, r5 ; @tls
  38. ; adjust libc args for syscall
  39. mov r0, r2 ; libc @flags is 1st syscall arg
  40. mov r2, r4 ; libc @ptid
  41. mov r3, r5 ; libc @tls
  42. mov r4, r6 ; libc @ctid
  43. mov r8, __NR_clone
  44. ARC_TRAP_INSN
  45. cmp r0, 0 ; return code : 0 new process, !0 parent
  46. blt .L__sys_err2 ; < 0 (signed) error
  47. jnz [blink] ; Parent returns
  48. ; ----- child starts here ---------
  49. #if defined(__UCLIBC_HAS_TLS__)
  50. ; Setup TP register (since kernel doesn't do that)
  51. and.f 0, r12, CLONE_SETTLS
  52. bz .Lnext_clone_quirk
  53. SET_TP r9
  54. .Lnext_clone_quirk:
  55. #ifdef RESET_PID
  56. bbit1 r12, 16, .Lgo_thread ; CLONE_THREAD = (1 << 16)
  57. mov r8, __NR_getpid
  58. ARC_TRAP_INSN ; r0 has PID
  59. THREAD_SELF r1 ; Get to struct pthread (just before TCB)
  60. st r0, [r1, PTHREAD_PID]
  61. st r0, [r1, PTHREAD_TID]
  62. .Lgo_thread:
  63. #endif
  64. #endif
  65. ; child jumps off to @fn with @arg as argument, and returns here
  66. jl.d [r10]
  67. mov r0, r11
  68. ; falls thru to _exit() with result from @fn (already in r0)
  69. b HIDDEN_JUMPTARGET(_exit)
  70. .L__sys_err:
  71. mov r0, -EINVAL
  72. .L__sys_err2:
  73. ; (1) No need to make -ve kernel error code as positive errno
  74. ; __syscall_error expects the -ve error code returned by kernel
  75. ; (2) r0 still had orig -ve kernel error code
  76. ; (3) Tail call to __syscall_error so we dont have to come back
  77. ; here hence instead of jmp-n-link (reg push/pop) we do jmp
  78. ; (4) No need to route __syscall_error via PLT, B is inherently
  79. ; position independent
  80. b __syscall_error
  81. END(clone)
  82. libc_hidden_def(clone)