]>
Commit | Line | Data |
---|---|---|
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 | |
43 | ENTRY (__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 | } | |
219 | PSEUDO_END (__clone) | |
220 | ||
221 | weak_alias (__clone, clone) |