clone.S 2.6 KB

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