clone.S 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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_VM 0x00000100
  27. #define CLONE_THREAD 0x00010000
  28. #define CLONE_SETTLS 0x00080000
  29. #define CLONE_THREAD_N_VM (CLONE_THREAD | CLONE_VM)
  30. ENTRY(clone)
  31. cmp r0, 0 ; @fn can't be NULL
  32. cmp.ne r1, 0 ; @child_stack can't be NULL
  33. bz .L__sys_err
  34. ; save some of the orig args
  35. ; r0 containg @fn will be clobbered AFTER syscall (with ret val)
  36. ; rest are clobbered BEFORE syscall due to different arg ordering
  37. mov r10, r0 ; @fn
  38. mov r11, r3 ; @args
  39. mov r12, r2 ; @clone_flags
  40. mov r9, r5 ; @tls
  41. ; adjust libc args for syscall
  42. mov r0, r2 ; libc @flags is 1st syscall arg
  43. mov r2, r4 ; libc @ptid
  44. mov r3, r5 ; libc @tls
  45. mov r4, r6 ; libc @ctid
  46. mov r8, __NR_clone
  47. ARC_TRAP_INSN
  48. cmp r0, 0 ; return code : 0 new process, !0 parent
  49. blt .L__sys_err2 ; < 0 (signed) error
  50. jnz [blink] ; Parent returns
  51. ; ----- child starts here ---------
  52. #if defined(__UCLIBC_HAS_TLS__)
  53. ; Setup TP register (since kernel doesn't do that)
  54. and.f 0, r12, CLONE_SETTLS
  55. bz .Lnext_clone_quirk
  56. SET_TP r9
  57. .Lnext_clone_quirk:
  58. #ifdef RESET_PID
  59. mov_s r2, CLONE_THREAD_N_VM
  60. and_s r2, r2, r12
  61. brne r2, r12, .Lgo_thread
  62. mov r8, __NR_clone
  63. ARC_TRAP_INSN ; r0 has PID
  64. THREAD_SELF r1 ; Get to struct pthread (just before TCB)
  65. st r0, [r1, PTHREAD_PID]
  66. st r0, [r1, PTHREAD_TID]
  67. .Lgo_thread:
  68. #endif
  69. #endif
  70. ; child jumps off to @fn with @arg as argument, and returns here
  71. jl.d [r10]
  72. mov r0, r11
  73. ; falls thru to _exit() with result from @fn (already in r0)
  74. b HIDDEN_JUMPTARGET(_exit)
  75. .L__sys_err:
  76. mov r0, -EINVAL
  77. .L__sys_err2:
  78. ; (1) No need to make -ve kernel error code as positive errno
  79. ; __syscall_error expects the -ve error code returned by kernel
  80. ; (2) r0 still had orig -ve kernel error code
  81. ; (3) Tail call to __syscall_error so we dont have to come back
  82. ; here hence instead of jmp-n-link (reg push/pop) we do jmp
  83. ; (4) No need to route __syscall_error via PLT, B is inherently
  84. ; position independent
  85. b __syscall_error
  86. END(clone)
  87. libc_hidden_def(clone)