]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/tile/clone.S
tile: move sysdeps/unix/sysv/linux/tile nptl files.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / tile / clone.S
CommitLineData
d4697bc9 1/* Copyright (C) 2011-2014 Free Software Foundation, Inc.
63d143a2
CM
2 This file is part of the GNU C Library.
3 Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
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
ab84e3ff
PE
16 License along with the GNU C Library. If not, see
17 <http://www.gnu.org/licenses/>. */
63d143a2
CM
18
19/* clone() is even more special than fork() as it mucks with stacks
20 and invokes a function in the right context after it's all over. */
21
22#include <sysdep.h>
23#define _ERRNO_H 1
24#include <bits/errno.h>
25
26#include <asm/unistd.h>
27#include <arch/abi.h>
28#include <tls.h>
29#include <linux/sched.h>
30
31/* What we save where in the stack frame; must include all callee-saves. */
32#define FRAME_NEXT_LR (0 * REGSIZE) /* reserved by ABI; not used here */
33#define FRAME_SP (1 * REGSIZE)
34#define FRAME_R30 (2 * REGSIZE)
35#define FRAME_R31 (3 * REGSIZE)
36#define FRAME_R32 (4 * REGSIZE)
37#define FRAME_SIZE (5 * REGSIZE)
38
39/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
40 pid_t *ptid, struct user_desc *tls, pid_t *ctid); */
41
42 .text
43ENTRY (__clone)
44 /* sanity check arguments */
45 BEQZ r0, .Linvalid
46 BEQZ r1, .Linvalid
47
48 /* Create a stack frame so we can pass callee-saves to new task. */
49 {
50 move r10, sp
51 ST sp, lr
52 ADDI_PTR sp, sp, -FRAME_SIZE
53 }
54 cfi_offset (lr, 0)
55 cfi_def_cfa_offset (FRAME_SIZE)
56 ADDI_PTR r11, sp, FRAME_SP
57 {
58 ST r11, r10
59 ADDI_PTR r11, sp, FRAME_R30
60 }
61 {
62 ST r11, r30
63 ADDI_PTR r11, sp, FRAME_R31
64 }
65 cfi_offset (r30, FRAME_R30 - FRAME_SIZE)
66 {
67 ST r11, r31
68 ADDI_PTR r11, sp, FRAME_R32
69 }
70 cfi_offset (r31, FRAME_R31 - FRAME_SIZE)
71 ST r11, r32
72 cfi_offset (r32, FRAME_R32 - FRAME_SIZE)
73
74 /* Make sure child stack is properly aligned, and set up the
75 top frame so that we can call out of it immediately in the
76 child. Setting it up here means we fault in the parent if
77 it's bogus, which is probably cleaner than faulting first
78 thing in the child. */
79 ADDI_PTR r1, r1, -C_ABI_SAVE_AREA_SIZE
80 andi r1, r1, -C_ABI_SAVE_AREA_SIZE
81 ADDI_PTR r9, r1, REGSIZE /* sp of this frame on entry, i.e. zero */
82 ST r9, zero
83
84 /* We need to switch the argument convention around from
85 libc to kernel:
5556231d 86
63d143a2
CM
87 libc:
88 r0 fn
89 r1 child_stack
90 r2 flags
91 r3 arg
92 r4 ptid
93 r5 tls
94 r6 ctid
5556231d 95
63d143a2
CM
96 kernel:
97 r0 flags
98 r1 child_stack [same as libc]
99 r2 ptid
100 r3 ctid
101 r4 tls
5556231d 102
63d143a2
CM
103 Plus the callee-saves as described at .Lthread_start, below. */
104 {
105 move r32, r0
106 move r0, r2
107 }
108 {
109 move r31, r3
110 move r3, r6
111 }
112 {
113 move r30, r2
114 move r2, r4
115 }
116 {
117 move r4, r5
118 moveli TREG_SYSCALL_NR_NAME, __NR_clone
119 }
120 swint1
121 BEQZ r0, .Lthread_start /* If in child task. */
122
123 /* Restore the callee-saved registers and return. */
124 ADDLI_PTR lr, sp, FRAME_SIZE
125 {
126 LD lr, lr
127 ADDLI_PTR r30, sp, FRAME_R30
128 }
129 {
130 LD r30, r30
131 ADDLI_PTR r31, sp, FRAME_R31
132 }
133 {
134 LD r31, r31
135 ADDLI_PTR r32, sp, FRAME_R32
136 }
137 {
138 LD r32, r32
139 ADDI_PTR sp, sp, FRAME_SIZE
140 }
141 cfi_def_cfa_offset (0)
142
143 BNEZ r1, .Lerror
144 jrp lr
145
146.Lerror:
147 j SYSCALL_ERROR_NAME
148
149.Linvalid:
150 {
151 movei r1, EINVAL
152 j SYSCALL_ERROR_NAME
153 }
5556231d 154
63d143a2 155/* This function expects to receive:
5556231d 156
63d143a2
CM
157 sp: the top of a valid stack area
158 r30: clone() flags
159 r31: the argument to pass to the user function
160 r32: the user function pointer */
161
162.Lthread_start:
2bc2d8e8
CM
163 cfi_def_cfa_offset (FRAME_SIZE)
164 cfi_undefined (lr)
63d143a2
CM
165 /* Check and see if we need to reset the PID, which we do if
166 CLONE_THREAD isn't set, i.e. we're not staying in the thread group.
167 If CLONE_VM is set, we're doing some kind of thread-like clone,
168 so we set the tid/pid to -1 to disable using the cached values
169 in getpid(). Otherwise (if CLONE_VM isn't set), it's a
170 fork-like clone, and we go ahead and write the cached values
171 from the true system pid (retrieved via __NR_getpid syscall). */
172#ifdef __tilegx__
173 {
174 moveli r0, hw1_last(CLONE_VM)
175 moveli r1, hw1_last(CLONE_THREAD)
176 }
177 {
178 shl16insli r0, r0, hw0(CLONE_VM)
179 shl16insli r1, r1, hw0(CLONE_THREAD)
180 }
181#else
182 {
183 moveli r0, lo16(CLONE_VM)
184 moveli r1, lo16(CLONE_THREAD)
185 }
186 {
187 auli r0, r0, ha16(CLONE_VM)
188 auli r1, r1, ha16(CLONE_THREAD)
189 }
190#endif
191 {
192 and r0, r30, r0
193 and r1, r30, r1
194 }
195 BNEZ r1, .Lno_reset_pid /* CLONE_THREAD is set */
196 {
197 movei r0, -1
198 BNEZ r0, .Lgotpid /* CLONE_VM is set */
199 }
200 moveli TREG_SYSCALL_NR_NAME, __NR_getpid
201 swint1
202.Lgotpid:
203 ADDLI_PTR r2, tp, PID_OFFSET
204 {
205 ST4 r2, r0
206 ADDLI_PTR r2, tp, TID_OFFSET
207 }
208 ST4 r2, r0
209.Lno_reset_pid:
210 {
211 /* Invoke user function with specified argument. */
212 move r0, r31
213 jalr r32
214 }
215 {
216 j HIDDEN_JUMPTARGET(_exit)
217 info INFO_OP_CANNOT_BACKTRACE /* Notify backtracer to stop. */
218 }
219PSEUDO_END (__clone)
220
221weak_alias (__clone, clone)