f2964f48716c3bfbc428b9c69b65e2568edff40b
[jlayton/glibc.git] / ports / sysdeps / unix / sysv / linux / aarch64 / clone.S
1 /* Copyright (C) 1996-2014 Free Software Foundation, Inc.
2
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 /* clone() is even more special than fork() as it mucks with stacks
20    and invokes a function in the right context after its all over.  */
21
22 #include <sysdep.h>
23 #define _ERRNO_H        1
24 #include <bits/errno.h>
25
26 #define CLONE_VM_BIT      8
27 #define CLONE_VM          (1 << CLONE_VM_BIT)
28
29 #define CLONE_THREAD_BIT  16
30 #define CLONE_THREAD      (1 << CLONE_THREAD_BIT)
31
32 /* int clone(int (*fn)(void *arg),            x0
33              void *child_stack,               x1
34              int flags,                       x2
35              void *arg,                       x3
36              pid_t *ptid,                     x4
37              struct user_desc *tls,           x5
38              pid_t *ctid);                    x6
39  */
40         .text
41 ENTRY(__clone)
42         /* Sanity check args.  */
43         cbz     x0, 1f
44         cbz     x1, 1f
45         /* Insert the args onto the new stack.  */
46         stp     x0, x3, [x1, #-16]!     /* Fn, arg.  */
47
48         /* Do the system call.  */
49         mov     x0, x2                  /* flags  */
50
51         /* New sp is already in x1.  */
52         mov     x2, x4                  /* ptid  */
53         mov     x3, x5                  /* tls  */
54         mov     x4, x6                  /* ctid  */
55
56 #ifdef RESET_PID
57         /* We rely on the kernel preserving the argument regsiters across a
58            each system call so that we can inspect the flags against after
59            the clone call.  */
60         mov     x5, x0
61 #endif
62
63         mov     x8, #SYS_ify(clone)
64         /* X0:flags, x1:newsp, x2:parenttidptr, x3:newtls, x4:childtid.  */
65         svc     0x0
66         cfi_endproc
67         cmp     x0, #0
68         beq     2f
69         blt     3f
70         RET
71 1:      mov     x0, #-EINVAL
72 3:
73         b       syscall_error
74
75 2:
76         cfi_startproc
77         cfi_undefined (x30)
78         mov     x29, 0
79 #ifdef RESET_PID
80         tbnz    x5, #CLONE_THREAD_BIT, 3f
81         mov     x0, #-1
82         tbnz    x5, #CLONE_VM_BIT, 2f
83         mov     x8, #SYS_ify(getpid)
84         svc     0x0
85 2:
86         mrs     x1, tpidr_el0
87         sub     x1, x1, #PTHREAD_SIZEOF
88         str     w0, [x1, #PTHREAD_PID_OFFSET]
89         str     w0, [x1, #PTHREAD_TID_OFFSET]
90
91 3:
92 #endif
93         /* Pick the function arg and call address from the stack and
94            execute.  */
95         ldp     x1, x0, [sp], #16
96         blr     x1
97
98         /* We are done, pass the return value through x0.  */
99         b       HIDDEN_JUMPTARGET(_exit)
100         cfi_endproc
101         cfi_startproc
102 PSEUDO_END (__clone)
103
104 weak_alias (__clone, clone)