]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 1999-2007 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | /* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved. | |
29 | * | |
30 | * File: libc/ppc/sys/fork.s | |
31 | * | |
32 | * HISTORY | |
33 | * 18-Nov-92 Ben Fathi (benf@next.com) | |
34 | * Created from M88K sources | |
35 | * | |
36 | * 11-Jan-92 Peter King (king@next.com) | |
37 | * Created from M68K sources | |
38 | */ | |
39 | ||
40 | #include "SYS.h" | |
41 | ||
42 | #if defined(__ppc__) || defined(__ppc64__) | |
43 | ||
44 | /* We use mode-independent "g" opcodes such as "srgi". These expand | |
45 | * into word operations when targeting __ppc__, and into doubleword | |
46 | * operations when targeting __ppc64__. | |
47 | */ | |
48 | #include <architecture/ppc/mode_independent_asm.h> | |
49 | ||
50 | MI_ENTRY_POINT(___fork) | |
51 | MI_PUSH_STACK_FRAME | |
52 | ||
53 | MI_CALL_EXTERNAL(__cthread_fork_prepare) | |
54 | ||
55 | li r0,SYS_fork | |
56 | sc // do the fork | |
57 | b Lbotch // error return | |
58 | ||
59 | cmpwi r4,0 // parent (r4==0) or child (r4==1) ? | |
60 | beq Lparent // parent, since r4==0 | |
61 | ||
62 | ||
63 | /* Here if we are the child. */ | |
64 | ||
65 | #if defined(__DYNAMIC__) | |
66 | .cstring | |
67 | LC3: | |
68 | .ascii "__dyld_fork_child\0" | |
69 | .text | |
70 | .align 2 | |
71 | mflr r0 | |
72 | bcl 20,31,1f | |
73 | 1: mflr r3 | |
74 | mtlr r0 | |
75 | addis r3,r3,ha16(LC3-1b) | |
76 | addi r3,r3,lo16(LC3-1b) | |
77 | addi r4,r1,SF_LOCAL1 | |
78 | bl __dyld_func_lookup | |
79 | lg r3,SF_LOCAL1(r1) | |
80 | mtspr ctr,r3 | |
81 | bctrl | |
82 | #endif | |
83 | ||
84 | li r9,0 | |
85 | MI_GET_ADDRESS(r8,__current_pid) | |
86 | stw r9,0(r8) // clear cached pid in child | |
87 | ||
88 | MI_CALL_EXTERNAL(__cthread_fork_child) | |
89 | ||
90 | li r3,0 // flag for "we are the child" | |
91 | b Lreturn | |
92 | ||
93 | ||
94 | /* Here if we are the parent, with: | |
95 | * r3 = child's pid | |
96 | */ | |
97 | Lparent: | |
98 | stg r3,SF_LOCAL2(r1) // save child pid in stack | |
99 | ||
100 | b Lparent_return // clean up and return child's pid | |
101 | ||
102 | ||
103 | /* Here if the fork() syscall failed. We're still the parent. */ | |
104 | ||
105 | Lbotch: | |
106 | ||
107 | MI_CALL_EXTERNAL(cerror) | |
108 | li r3,-1 // get an error return code | |
109 | stg r3,SF_LOCAL2(r1) // save return code in stack | |
110 | ||
111 | /* | |
112 | * We use cthread_fork_parent() to clean up after a fork error | |
113 | * (unlock cthreads and mailloc packages) so the parent | |
114 | * process can Malloc() after fork() errors without | |
115 | * deadlocking. | |
116 | */ | |
117 | ||
118 | Lparent_return: | |
119 | MI_CALL_EXTERNAL(__cthread_fork_parent) | |
120 | lg r3,SF_LOCAL2(r1) // return -1 on error, child's pid on success | |
121 | ||
122 | Lreturn: | |
123 | MI_POP_STACK_FRAME_AND_RETURN | |
124 | ||
125 | #elif defined(__i386__) | |
126 | ||
127 | LEAF(___fork, 0) | |
128 | subl $28, %esp // Align the stack, with 16 bytes of extra padding that we'll need | |
129 | CALL_EXTERN(__cthread_fork_prepare) | |
130 | ||
131 | movl $ SYS_fork,%eax; // code for fork -> eax | |
132 | UNIX_SYSCALL_TRAP // do the system call | |
133 | jnc L1 // jump if CF==0 | |
134 | ||
135 | CALL_EXTERN(cerror) | |
136 | CALL_EXTERN(__cthread_fork_parent) | |
137 | movl $-1,%eax | |
138 | addl $28, %esp // restore the stack | |
139 | ret | |
140 | ||
141 | L1: | |
142 | orl %edx,%edx // CF=OF=0, ZF set if zero result | |
143 | jz L2 // parent, since r1 == 0 in parent, 1 in child | |
144 | ||
145 | //child here... | |
146 | #if defined(__DYNAMIC__) | |
147 | // Here on the child side of the fork we need to tell the dynamic linker that | |
148 | // we have forked. To do this we call __dyld_fork_child in the dyanmic | |
149 | // linker. But since we can't dynamically bind anything until this is done we | |
150 | // do this by using the private extern __dyld_func_lookup() function to get the | |
151 | // address of __dyld_fork_child (the 'C' code equivlent): | |
152 | // | |
153 | // _dyld_func_lookup("__dyld_fork_child", &address); | |
154 | // address(); | |
155 | // | |
156 | .cstring | |
157 | LC0: | |
158 | .ascii "__dyld_fork_child\0" | |
159 | ||
160 | .text | |
161 | leal 0x8(%esp),%eax // get the address where we're going to store the pointer | |
162 | movl %eax, 0x4(%esp) // copy the address of the pointer | |
163 | call 1f | |
164 | 1: popl %eax | |
165 | leal LC0-1b(%eax),%eax | |
166 | movl %eax, 0x0(%esp) // copy the name of the function to look up | |
167 | call __dyld_func_lookup | |
168 | movl 0x8(%esp),%eax // move the value returned in address parameter | |
169 | call *%eax // call __dyld_fork_child indirectly | |
170 | #endif | |
171 | xorl %eax, %eax | |
172 | REG_TO_EXTERN(%eax, __current_pid) | |
173 | CALL_EXTERN(__cthread_fork_child) | |
174 | ||
175 | xorl %eax,%eax // zero eax | |
176 | addl $28, %esp // restore the stack | |
177 | ret | |
178 | ||
179 | //parent here... | |
180 | L2: | |
181 | movl %eax, 0xc(%esp) // save pid | |
182 | ||
183 | CALL_EXTERN_AGAIN(__cthread_fork_parent) | |
184 | movl 0xc(%esp), %eax // return pid | |
185 | addl $28, %esp // restore the stack | |
186 | ret | |
187 | ||
188 | #elif defined(__x86_64__) | |
189 | ||
190 | LEAF(___fork, 0) | |
191 | subq $24, %rsp // Align the stack, plus room for local storage | |
192 | CALL_EXTERN(__cthread_fork_prepare) | |
193 | ||
194 | movl $ SYSCALL_CONSTRUCT_UNIX(SYS_fork),%eax; // code for fork -> rax | |
195 | UNIX_SYSCALL_TRAP // do the system call | |
196 | jnc L1 // jump if CF==0 | |
197 | ||
198 | CALL_EXTERN(cerror) | |
199 | CALL_EXTERN(__cthread_fork_parent) | |
200 | movq $-1, %rax | |
201 | addq $24, %rsp // restore the stack | |
202 | ret | |
203 | ||
204 | L1: | |
205 | orl %edx,%edx // CF=OF=0, ZF set if zero result | |
206 | jz L2 // parent, since r1 == 0 in parent, 1 in child | |
207 | ||
208 | //child here... | |
209 | #if defined(__DYNAMIC__) | |
210 | // Here on the child side of the fork we need to tell the dynamic linker that | |
211 | // we have forked. To do this we call __dyld_fork_child in the dyanmic | |
212 | // linker. But since we can't dynamically bind anything until this is done we | |
213 | // do this by using the private extern __dyld_func_lookup() function to get the | |
214 | // address of __dyld_fork_child (the 'C' code equivlent): | |
215 | // | |
216 | // _dyld_func_lookup("__dyld_fork_child", &address); | |
217 | // address(); | |
218 | // | |
219 | .cstring | |
220 | LC0: | |
221 | .ascii "__dyld_fork_child\0" | |
222 | ||
223 | .text | |
224 | leaq 8(%rsp),%rsi // get the address where we're going to store the pointer | |
225 | leaq LC0(%rip), %rdi // copy the name of the function to look up | |
226 | call __dyld_func_lookup | |
227 | call *8(%rsp) // call __dyld_fork_child indirectly | |
228 | #endif | |
229 | xorq %rax, %rax | |
230 | REG_TO_EXTERN(%rax, __current_pid) | |
231 | CALL_EXTERN(__cthread_fork_child) | |
232 | ||
233 | xorq %rax,%rax // zero rax | |
234 | addq $24, %rsp // restore the stack | |
235 | ret | |
236 | ||
237 | //parent here... | |
238 | L2: | |
239 | movl %eax, 16(%rsp) // save pid | |
240 | ||
241 | CALL_EXTERN_AGAIN(__cthread_fork_parent) | |
242 | movl 16(%rsp), %eax // return pid | |
243 | addq $24, %rsp // restore the stack | |
244 | ret | |
245 | ||
246 | #elif defined(__arm__) | |
247 | ||
248 | .globl cerror | |
249 | MI_ENTRY_POINT(_fork) | |
250 | stmfd sp!, {r4, r7, lr} | |
251 | add r7, sp, #4 | |
252 | MI_CALL_EXTERNAL(__cthread_fork_prepare) | |
253 | mov r1, #1 // prime results | |
254 | mov r12, #SYS_fork | |
255 | swi #SWI_SYSCALL // make the syscall | |
256 | bcs Lbotch // error? | |
257 | cmp r1, #0 // parent (r1=0) or child(r1=1) | |
258 | beq Lparent | |
259 | ||
260 | //child here... | |
261 | MI_GET_ADDRESS(r3, __current_pid) | |
262 | mov r0, #0 | |
263 | str r0, [r3] // clear cached pid in child | |
264 | ||
265 | #if defined(__DYNAMIC__) | |
266 | // Here on the child side of the fork we need to tell the dynamic linker that | |
267 | // we have forked. To do this we call __dyld_fork_child in the dyanmic | |
268 | // linker. But since we can't dynamicly bind anything until this is done we | |
269 | // do this by using the private extern __dyld_func_lookup() function to get the | |
270 | // address of __dyld_fork_child (the 'C' code equivlent): | |
271 | // | |
272 | // _dyld_func_lookup("__dyld_fork_child", &address); | |
273 | // address(); | |
274 | // | |
275 | .cstring | |
276 | .align 2 | |
277 | LC0: | |
278 | .ascii "__dyld_fork_child\0" | |
279 | .text | |
280 | .align 2 | |
281 | sub sp, sp, #4 // allocate space for the address parameter | |
282 | mov r1, sp // get the address of the allocated space | |
283 | ldr r0, LP0 // get the name of the function to look up | |
284 | L0: add r0, pc, r0 | |
285 | bl __dyld_func_lookup | |
286 | mov lr, pc | |
287 | ldr pc, [sp], #4 // call __dyld_fork_child indirectly and pop | |
288 | #endif | |
289 | MI_CALL_EXTERNAL(__cthread_fork_child) // let child get ready | |
290 | mov r0, #0 | |
291 | ldmfd sp!, {r4, r7, pc} | |
292 | ||
293 | Lbotch: | |
294 | MI_CALL_EXTERNAL(cerror) // jump here on error | |
295 | mov r0,#-1 // set the error | |
296 | // fall thru | |
297 | ||
298 | Lparent: | |
299 | mov r4, r0 // save child pid | |
300 | MI_CALL_EXTERNAL(__cthread_fork_parent) | |
301 | mov r0, r4 // restore child pid | |
302 | ldmfd sp!, {r4, r7, pc} // pop and return | |
303 | ||
304 | .align 2 | |
305 | #if defined(__DYNAMIC__) | |
306 | LP0: | |
307 | .long LC0-(L0+8) | |
308 | #endif | |
309 | ||
310 | #else | |
311 | #error Unsupported architecture | |
312 | #endif |